commit 57897fe670ecbe13e70032167987b8ba2bd65c3d
Author: Edea Kramer <edea@lunarcry.my.domain>
Date: Wed, 20 Mar 2024 10:15:57 +0200
First commit
Diffstat:
18 files changed, 38199 insertions(+), 0 deletions(-)
diff --git a/compile b/compile
@@ -0,0 +1 @@
+cc -std=c89 -Wall -pedantic -g src/*.c
diff --git a/include/bios.h b/include/bios.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "types.h"
+
+struct BIOS {
+ u8* data;
+};
+
+typedef struct BIOS BIOS;
+
+BIOS* BIOS_new(const char*);
+u32 BIOS_load32(BIOS*, u32);
diff --git a/include/cpu.h b/include/cpu.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include "../include/interconnect.h"
+#include "../include/types.h"
+
+#define IMM_JUMP(i) (i & 0x3ffffff)
+#define IMM_SE(i) (((u32)((i16)(i & 0xffff))));
+
+struct instruction {
+ u32 _0;
+ u32 fn;
+ u32 t;
+ u32 s;
+ u32 d;
+ u32 imm;
+ u32 imm_se;
+ u32 imm_jump;
+ u32 sub;
+ u32 shift;
+ u32 cop_opcode;
+};
+
+typedef struct instruction instruction;
+
+struct load {
+ u32 _0;
+ u32 _1;
+};
+
+typedef struct load load;
+
+struct CPU {
+
+ /* Program Counter register */
+ u32 pc;
+
+ /* Cop0 register 12: Status Register*/
+ u32 sr;
+
+ instruction next_instruction;
+
+ Interconnect* inter;
+
+ /* General Registers */
+ u32 regs[32];
+
+ /* Second set of regs to emulate the LOAD DELAY SLOT.
+ They contain the output of the current instruction */
+ u32 out_regs[32];
+
+ /* LOAD -> on load delay slots */
+ load load;
+
+};
+
+typedef struct CPU CPU;
+
+CPU* new_cpu(Interconnect*);
+u32 CPU_load32(CPU*, u32);
+void CPU_decode_and_execute(CPU*, instruction*);
+void CPU_run_next_instruction(CPU*);
+
+instruction new_instr(u32);
+void print_instr(instruction*);
diff --git a/include/defs.h b/include/defs.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#define LOG_ERR(x) fprintf(stderr, (x))
+
+#define PANIC(...) do { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } while(0)
diff --git a/include/interconnect.h b/include/interconnect.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "../include/bios.h"
+#include "../include/mem.h"
+#include "../include/types.h"
+
+struct Interconnect {
+ BIOS* BIOS;
+ RAM* RAM;
+};
+
+typedef struct Interconnect Interconnect;
+
+Interconnect* new_interconnect(void);
+u32 INTER_load32(Interconnect*, u32);
+void INTER_store32(Interconnect*, u32, u32);
diff --git a/include/mem.h b/include/mem.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "util.h"
+#include "types.h"
+
+struct RAM {
+ u8* data;
+};
+
+typedef struct RAM RAM;
+
+RAM* RAM_new(void);
+u32 RAM_load32(RAM*, u32);
+void RAM_store32(RAM* r, u32, u32);
diff --git a/include/types.h b/include/types.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <stdint.h>
+
+#define TRUE 1
+#define FALSE 0
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+typedef int8_t i8;
+typedef int16_t i16;
+typedef int32_t i32;
+typedef int64_t i64;
+typedef uint8_t Bool;
diff --git a/include/util.h b/include/util.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "types.h"
+
+#define BIOS_SIZE 512 * 1024
+#define BIOS_START 0xBFC00000
+
+#define SYSCONTROL_SIZE 36
+#define SYSCONTROL_START 0x1F801000
+
+#define RAM_SIZE_SIZE 4
+#define RAM_SIZE_START 0x1F801060
+
+#define CACHECONTROL_SIZE 4
+#define CACHECONTROL_START 0xFFFE0130
+
+#define RAM_SIZE 2 * 1024 * 1024
+#define RAM_START 0xA0000000
+
+
+u32 UTIL_contains(u32, u32, u32);
diff --git a/misc/psx.txt b/misc/psx.txt
@@ -0,0 +1,37593 @@
+Contents
+--------
+
+Nocash PSXSPX Playstation Specifications
+--> Memory Map
+--> I/O Map
+--> Graphics Processing Unit (GPU)
+--> Geometry Transformation Engine (GTE)
+--> Macroblock Decoder (MDEC)
+--> Sound Processing Unit (SPU)
+--> Interrupts
+--> DMA Channels
+--> Timers
+--> CDROM Drive
+--> CDROM File Formats
+--> Controllers and Memory Cards
+--> Pocketstation
+--> Serial Port (SIO)
+--> Expansion Port (PIO)
+--> Memory Control
+--> Unpredictable Things
+--> CPU Specifications
+--> Kernel (BIOS)
+--> Arcade Cabinets
+--> Cheat Devices
+--> PSX Dev-Board Chipsets
+--> Hardware Numbers
+--> Pinouts
+--> About & Credits
+
+Latest Research
+--> CDROM File Formats
+
+Nocash PSX Emulator/Debugger
+--> No$psx Emulation Controls
+--> No$psx Emulation Files
+--> No$psx Emulation Notes
+--> No$psx Debugger - Hotkeys in Debug Mode
+--> No$psx Debugger - Breakpoints
+--> No$psx Debugger - General Debug Features
+
+
+Memory Map
+----------
+
+Memory Map
+ KUSEG KSEG0 KSEG1
+ 00000000h 80000000h A0000000h 2048K Main RAM (first 64K reserved for BIOS)
+ 1F000000h 9F000000h BF000000h 8192K Expansion Region 1 (ROM/RAM)
+ 1F800000h 9F800000h -- 1K Scratchpad (D-Cache used as Fast RAM)
+ 1F801000h 9F801000h BF801000h 8K I/O Ports
+ 1F802000h 9F802000h BF802000h 8K Expansion Region 2 (I/O Ports)
+ 1FA00000h 9FA00000h BFA00000h 2048K Expansion Region 3 (whatever purpose)
+ 1FC00000h 9FC00000h BFC00000h 512K BIOS ROM (Kernel) (4096K max)
+ FFFE0000h (KSEG2) 0.5K I/O Ports (Cache Control)
+Additionally, there are a number of memory mirrors.
+
+Additional Memory (not mapped to the CPU bus)
+ 1024K VRAM (Framebuffers, Textures, Palettes) (with 2KB Texture Cache)
+ 512K Sound RAM (Capture Buffers, ADPCM Data, Reverb Workspace)
+ 0.5K CDROM controller RAM (see CDROM Test commands)
+ 16.5K CDROM controller ROM (Firmware and Bootstrap for MC68HC05 cpu)
+ 32K CDROM Buffer (IC303) (32Kx8) (BUG: only two sectors accessible?)
+ 128K External Memory Card(s) (EEPROMs)
+
+KUSEG,KSEG0,KSEG1,KSEG2 Memory Regions
+ Address Name Size Privilege Code-Cache Data-Cache
+ 00000000h KUSEG 2048M Kernel/User Yes (Scratchpad)
+ 80000000h KSEG0 512M Kernel Yes (Scratchpad)
+ A0000000h KSEG1 512M Kernel No No
+ C0000000h KSEG2 1024M Kernel (No code) No
+Kernel Memory: KSEG1 is the normal physical memory (uncached), KSEG0 is a
+mirror thereof (but with cache enabled). KSEG2 is usually intended to contain
+virtual kernel memory, in the PSX it's containing Cache Control I/O Ports.
+User Memory: KUSEG is intended to contain 2GB virtual memory (on extended MIPS
+processors), the PSX doesn't support virtual memory, and KUSEG simply contains
+a mirror of KSEG0/KSEG1 (in the first 512MB) (trying to access memory in the
+remaining 1.5GB causes an exception).
+
+Code Cache
+Works in the cached regions (KUSEG and KSEG0).
+There are reportedly some restrictions... not sure there... eventually it is
+using the LSBs of the address as cache-line number... so, for example, it
+couldn't simultaneously memorize opcodes at BOTH address 80001234h, AND at
+address 800F1234h (?)
+
+Data Cache aka Scratchpad
+The MIPS CPU usually have a Data Cache, but, in the PSX, Sony has misused it as
+"Scratchpad", that is, the "Data Cache" is mapped to a fixed memory location at
+1F800000h..1F8003FFh (ie. it's used as Fast RAM, rather than as cache).
+There <might> be a way to disable that behaviour (via Port FFFE0130h or so),
+but, the Kernel is accessing I/O ports via KUSEG, so activating Data Cache
+would cause the Kernel to access cached I/O ports.
+Not tested yet, but most probably the Scratchpad can be used only for Data (ie.
+NOT for program Code?).
+
+Memory Mirrors
+As described above, the 512Mbyte KUSEG, KSEG0, and KSEG1 regions are mirrors of
+each other. Additional mirrors within these 512MB regions are:
+ 2MB RAM can be mirrored to the first 8MB (strangely, enabled by default)
+ 512K BIOS ROM can be mirrored to the last 4MB (disabled by default)
+ Expansion hardware (if any) may be mirrored within expansion region
+ The seven DMA Control Registers at 1F8010x8h are mirrored to 1F8010xCh
+The size of the RAM, BIOS, Expansion regions can be configured by software, for
+Expansion Region it's also possible to change base address, see:
+--> Memory Control
+The Scratchpad is mirrored only in KUSEG and KSEG0, but not in KSEG1.
+
+Memory Exceptions
+ Memory Error ------> Misalignments
+ (and probably also KSEG access in User mode)
+ Bus Error ------> Unused Memory Regions (including Gaps in I/O Region)
+ (unless RAM/BIOS/Expansion mirrors are mapped to "unused" area)
+
+More Memory Info
+For Info on Exception vectors, Unused/Garbage memory locations, I/O Ports,
+Expansion ROM Headers, and Memory Waitstate Control, etc. see:
+--> I/O Map
+--> Memory Control
+--> EXP1 Expansion ROM Header
+--> BIOS Memory Map
+--> BIOS Memory Allocation
+--> COP0 - Exception Handling
+--> Unpredictable Things
+
+I/O Map
+-------
+
+Expansion Region 1
+ 1F000000h 80000h Expansion Region (default 512 Kbytes, max 8 MBytes)
+ 1F000000h 100h Expansion ROM Header (IDs and Entrypoints)
+Scratchpad
+ 1F800000h 400h Scratchpad (1K Fast RAM) (Data Cache mapped to fixed address)
+Memory Control 1
+ 1F801000h 4 Expansion 1 Base Address (usually 1F000000h)
+ 1F801004h 4 Expansion 2 Base Address (usually 1F802000h)
+ 1F801008h 4 Expansion 1 Delay/Size (usually 0013243Fh; 512Kbytes 8bit-bus)
+ 1F80100Ch 4 Expansion 3 Delay/Size (usually 00003022h; 1 byte)
+ 1F801010h 4 BIOS ROM Delay/Size (usually 0013243Fh; 512Kbytes 8bit-bus)
+ 1F801014h 4 SPU_DELAY Delay/Size (usually 200931E1h)
+ 1F801018h 4 CDROM_DELAY Delay/Size (usually 00020843h or 00020943h)
+ 1F80101Ch 4 Expansion 2 Delay/Size (usually 00070777h; 128-bytes 8bit-bus)
+ 1F801020h 4 COM_DELAY / COMMON_DELAY (00031125h or 0000132Ch or 00001325h)
+Peripheral I/O Ports
+ 1F801040h 1/4 JOY_DATA Joypad/Memory Card Data (R/W)
+ 1F801044h 4 JOY_STAT Joypad/Memory Card Status (R)
+ 1F801048h 2 JOY_MODE Joypad/Memory Card Mode (R/W)
+ 1F80104Ah 2 JOY_CTRL Joypad/Memory Card Control (R/W)
+ 1F80104Eh 2 JOY_BAUD Joypad/Memory Card Baudrate (R/W)
+ 1F801050h 1/4 SIO_DATA Serial Port Data (R/W)
+ 1F801054h 4 SIO_STAT Serial Port Status (R)
+ 1F801058h 2 SIO_MODE Serial Port Mode (R/W)
+ 1F80105Ah 2 SIO_CTRL Serial Port Control (R/W)
+ 1F80105Ch 2 SIO_MISC Serial Port Internal Register (R/W)
+ 1F80105Eh 2 SIO_BAUD Serial Port Baudrate (R/W)
+Memory Control 2
+ 1F801060h 4/2 RAM_SIZE (usually 00000B88h; 2MB RAM mirrored in first 8MB)
+Interrupt Control
+ 1F801070h 2 I_STAT - Interrupt status register
+ 1F801074h 2 I_MASK - Interrupt mask register
+DMA Registers
+ 1F80108xh DMA0 channel 0 - MDECin
+ 1F80109xh DMA1 channel 1 - MDECout
+ 1F8010Axh DMA2 channel 2 - GPU (lists + image data)
+ 1F8010Bxh DMA3 channel 3 - CDROM
+ 1F8010Cxh DMA4 channel 4 - SPU
+ 1F8010Dxh DMA5 channel 5 - PIO (Expansion Port)
+ 1F8010Exh DMA6 channel 6 - OTC (reverse clear OT) (GPU related)
+ 1F8010F0h DPCR - DMA Control register
+ 1F8010F4h DICR - DMA Interrupt register
+ 1F8010F8h unknown
+ 1F8010FCh unknown
+Timers (aka Root counters)
+ 1F801100h 2 Timer 0 Current Counter Value (R/W) ;\
+ 1F801104h 2 Timer 0 Counter Mode (R/W) ; Dotclock
+ 1F801108h 2 Timer 0 Counter Target Value (R/W) ;/
+ 1F801110h 2 Timer 1 Current Counter Value (R/W) ;\
+ 1F801114h 2 Timer 1 Counter Mode (R/W) ; Horizontal Retrace
+ 1F801118h 2 Timer 1 Counter Target Value (R/W) ;/
+ 1F801120h 2 Timer 2 Current Counter Value (R/W) ;\
+ 1F801124h 2 Timer 2 Counter Mode (R/W) ; 1/8 system clock
+ 1F801128h 2 Timer 2 Counter Target Value (R/W) ;/
+CDROM Registers (Address.Read/Write.Index)
+ 1F801800h.x.x 1 CD Index/Status Register (Bit0-1 R/W, Bit2-7 Read Only)
+ 1F801801h.R.x 1 CD Response Fifo (R) (usually with Index1)
+ 1F801802h.R.x 1/2 CD Data Fifo - 8bit/16bit (R) (usually with Index0..1)
+ 1F801803h.R.0 1 CD Interrupt Enable Register (R)
+ 1F801803h.R.1 1 CD Interrupt Flag Register (R/W)
+ 1F801803h.R.2 1 CD Interrupt Enable Register (R) (Mirror)
+ 1F801803h.R.3 1 CD Interrupt Flag Register (R/W) (Mirror)
+ 1F801801h.W.0 1 CD Command Register (W)
+ 1F801802h.W.0 1 CD Parameter Fifo (W)
+ 1F801803h.W.0 1 CD Request Register (W)
+ 1F801801h.W.1 1 Unknown/unused
+ 1F801802h.W.1 1 CD Interrupt Enable Register (W)
+ 1F801803h.W.1 1 CD Interrupt Flag Register (R/W)
+ 1F801801h.W.2 1 Unknown/unused
+ 1F801802h.W.2 1 CD Audio Volume for Left-CD-Out to Left-SPU-Input (W)
+ 1F801803h.W.2 1 CD Audio Volume for Left-CD-Out to Right-SPU-Input (W)
+ 1F801801h.W.3 1 CD Audio Volume for Right-CD-Out to Right-SPU-Input (W)
+ 1F801802h.W.3 1 CD Audio Volume for Right-CD-Out to Left-SPU-Input (W)
+ 1F801803h.W.3 1 CD Audio Volume Apply Changes (by writing bit5=1)
+GPU Registers
+ 1F801810h.Write 4 GP0 Send GP0 Commands/Packets (Rendering and VRAM Access)
+ 1F801814h.Write 4 GP1 Send GP1 Commands (Display Control)
+ 1F801810h.Read 4 GPUREAD Read responses to GP0(C0h) and GP1(10h) commands
+ 1F801814h.Read 4 GPUSTAT Read GPU Status Register
+MDEC Registers
+ 1F801820h.Write 4 MDEC Command/Parameter Register (W)
+ 1F801820h.Read 4 MDEC Data/Response Register (R)
+ 1F801824h.Write 4 MDEC Control/Reset Register (W)
+ 1F801824h.Read 4 MDEC Status Register (R)
+SPU Voice 0..23 Registers
+ 1F801C00h+N*10h 4 Voice 0..23 Volume Left/Right
+ 1F801C04h+N*10h 2 Voice 0..23 ADPCM Sample Rate
+ 1F801C06h+N*10h 2 Voice 0..23 ADPCM Start Address
+ 1F801C08h+N*10h 4 Voice 0..23 ADSR Attack/Decay/Sustain/Release
+ 1F801C0Ch+N*10h 2 Voice 0..23 ADSR Current Volume
+ 1F801C0Eh+N*10h 2 Voice 0..23 ADPCM Repeat Address
+SPU Control Registers
+ 1F801D80h 4 Main Volume Left/Right
+ 1F801D84h 4 Reverb Output Volume Left/Right
+ 1F801D88h 4 Voice 0..23 Key ON (Start Attack/Decay/Sustain) (W)
+ 1F801D8Ch 4 Voice 0..23 Key OFF (Start Release) (W)
+ 1F801D90h 4 Voice 0..23 Channel FM (pitch lfo) mode (R/W)
+ 1F801D94h 4 Voice 0..23 Channel Noise mode (R/W)
+ 1F801D98h 4 Voice 0..23 Channel Reverb mode (R/W)
+ 1F801D9Ch 4 Voice 0..23 Channel ON/OFF (status) (R)
+ 1F801DA0h 2 Unknown? (R) or (W)
+ 1F801DA2h 2 Sound RAM Reverb Work Area Start Address
+ 1F801DA4h 2 Sound RAM IRQ Address
+ 1F801DA6h 2 Sound RAM Data Transfer Address
+ 1F801DA8h 2 Sound RAM Data Transfer Fifo
+ 1F801DAAh 2 SPU Control Register (SPUCNT)
+ 1F801DACh 2 Sound RAM Data Transfer Control
+ 1F801DAEh 2 SPU Status Register (SPUSTAT) (R)
+ 1F801DB0h 4 CD Volume Left/Right
+ 1F801DB4h 4 Extern Volume Left/Right
+ 1F801DB8h 4 Current Main Volume Left/Right
+ 1F801DBCh 4 Unknown? (R/W)
+SPU Reverb Configuration Area
+ 1F801DC0h 2 dAPF1 Reverb APF Offset 1
+ 1F801DC2h 2 dAPF2 Reverb APF Offset 2
+ 1F801DC4h 2 vIIR Reverb Reflection Volume 1
+ 1F801DC6h 2 vCOMB1 Reverb Comb Volume 1
+ 1F801DC8h 2 vCOMB2 Reverb Comb Volume 2
+ 1F801DCAh 2 vCOMB3 Reverb Comb Volume 3
+ 1F801DCCh 2 vCOMB4 Reverb Comb Volume 4
+ 1F801DCEh 2 vWALL Reverb Reflection Volume 2
+ 1F801DD0h 2 vAPF1 Reverb APF Volume 1
+ 1F801DD2h 2 vAPF2 Reverb APF Volume 2
+ 1F801DD4h 4 mSAME Reverb Same Side Reflection Address 1 Left/Right
+ 1F801DD8h 4 mCOMB1 Reverb Comb Address 1 Left/Right
+ 1F801DDCh 4 mCOMB2 Reverb Comb Address 2 Left/Right
+ 1F801DE0h 4 dSAME Reverb Same Side Reflection Address 2 Left/Right
+ 1F801DE4h 4 mDIFF Reverb Different Side Reflection Address 1 Left/Right
+ 1F801DE8h 4 mCOMB3 Reverb Comb Address 3 Left/Right
+ 1F801DECh 4 mCOMB4 Reverb Comb Address 4 Left/Right
+ 1F801DF0h 4 dDIFF Reverb Different Side Reflection Address 2 Left/Right
+ 1F801DF4h 4 mAPF1 Reverb APF Address 1 Left/Right
+ 1F801DF8h 4 mAPF2 Reverb APF Address 2 Left/Right
+ 1F801DFCh 4 vIN Reverb Input Volume Left/Right
+SPU Internal Registers
+ 1F801E00h+N*04h 4 Voice 0..23 Current Volume Left/Right
+ 1F801E60h 20h Unknown? (R/W)
+ 1F801E80h 180h Unknown? (Read: FFh-filled) (Unused or Write only?)
+Expansion Region 2 (default 128 bytes, max 8 KBytes)
+ 1F802000h 80h Expansion Region (8bit data bus, crashes on 16bit access?)
+Expansion Region 2 - Dual Serial Port (for TTY Debug Terminal)
+ 1F802020h/1st DUART Mode Register 1.A (R/W)
+ 1F802020h/2nd DUART Mode Register 2.A (R/W)
+ 1F802021h/Read DUART Status Register A (R)
+ 1F802021h/Write DUART Clock Select Register A (W)
+ 1F802022h/Read DUART Toggle Baud Rate Generator Test Mode (Read=Strobe)
+ 1F802022h/Write DUART Command Register A (W)
+ 1F802023h/Read DUART Rx Holding Register A (FIFO) (R)
+ 1F802023h/Write DUART Tx Holding Register A (W)
+ 1F802024h/Read DUART Input Port Change Register (R)
+ 1F802024h/Write DUART Aux. Control Register (W)
+ 1F802025h/Read DUART Interrupt Status Register (R)
+ 1F802025h/Write DUART Interrupt Mask Register (W)
+ 1F802026h/Read DUART Counter/Timer Current Value, Upper/Bit15-8 (R)
+ 1F802026h/Write DUART Counter/Timer Reload Value, Upper/Bit15-8 (W)
+ 1F802027h/Read DUART Counter/Timer Current Value, Lower/Bit7-0 (R)
+ 1F802027h/Write DUART Counter/Timer Reload Value, Lower/Bit7-0 (W)
+ 1F802028h/1st DUART Mode Register 1.B (R/W)
+ 1F802028h/2nd DUART Mode Register 2.B (R/W)
+ 1F802029h/Read DUART Status Register B (R)
+ 1F802029h/Write DUART Clock Select Register B (W)
+ 1F80202Ah/Read DUART Toggle 1X/16X Test Mode (Read=Strobe)
+ 1F80202Ah/Write DUART Command Register B (W)
+ 1F80202Bh/Read DUART Rx Holding Register B (FIFO) (R)
+ 1F80202Bh/Write DUART Tx Holding Register B (W)
+ 1F80202Ch/None DUART Reserved Register (neither R nor W)
+ 1F80202Dh/Read DUART Input Port (R)
+ 1F80202Dh/Write DUART Output Port Configuration Register (W)
+ 1F80202Eh/Read DUART Start Counter Command (Read=Strobe)
+ 1F80202Eh/Write DUART Set Output Port Bits Command (Set means Out=LOW)
+ 1F80202Fh/Read DUART Stop Counter Command (Read=Strobe)
+ 1F80202Fh/Write DUART Reset Output Port Bits Command (Reset means Out=HIGH)
+Expansion Region 2 - Int/Dip/Post
+ 1F802000h 1 DTL-H2000: ATCONS STAT (R)
+ 1F802002h 1 DTL-H2000: ATCONS DATA (R and W)
+ 1F802004h 2 DTL-H2000: Whatever 16bit data ?
+ 1F802030h 1/4 DTL-H2000: Secondary IRQ10 Flags
+ 1F802032h 1 DTL-H2000: Whatever IRQ Control ?
+ 1F802040h 1 DTL-H2000: Bootmode "Dip switches" (R)
+ 1F802041h 1 PSX: POST (external 7 segment display, indicate BIOS boot status)
+ 1F802042h 1 DTL-H2000: POST/LED (similar to POST) (other addr, 2-digit wide)
+ 1F802070h 1 PS2: POST2 (similar to POST, but PS2 BIOS uses this address)
+Expansion Region 2 - Nocash Emulation Expansion
+ 1F802060h Emu-Expansion ID1 "E" (R)
+ 1F802061h Emu-Expansion ID2 "X" (R)
+ 1F802062h Emu-Expansion ID3 "P" (R)
+ 1F802063h Emu-Expansion Version (01h) (R)
+ 1F802064h Emu-Expansion Enable1 "O" (R/W)
+ 1F802065h Emu-Expansion Enable2 "N" (R/W)
+ 1F802066h Emu-Expansion Halt (R)
+ 1F802067h Emu-Expansion Turbo Mode Flags (R/W)
+Expansion Region 3 (default 1 byte, max 2 MBytes)
+ 1FA00000h - Not used by BIOS or any PSX games
+ 1FA00000h - POST3 (similar to POST, but PS2 BIOS uses this address)
+BIOS Region (default 512 Kbytes, max 4 MBytes)
+ 1FC00000h 80000h BIOS ROM (512Kbytes) (Reset Entrypoint at BFC00000h)
+Memory Control 3 (Cache Control)
+ FFFE0130h 4 Cache Control
+
+Coprocessor Registers
+ COP0 System Control Coprocessor - 32 registers (not all used)
+ COP1 N/A
+ COP2 Geometry Transformation Engine (GTE) - 64 registers (most are used)
+ COP3 N/A
+
+Graphics Processing Unit (GPU)
+------------------------------
+
+The GPU can render Polygons, Lines, or Rectangles to the Drawing Buffer, and
+sends the Display Buffer to the Television Set. Polygons are useful for 3D
+graphics (or rotated/scaled 2D graphics), Rectangles are useful for 2D graphics
+and Text output.
+
+--> GPU I/O Ports, DMA Channels, Commands, VRAM
+--> GPU Render Polygon Commands
+--> GPU Render Line Commands
+--> GPU Render Rectangle Commands
+--> GPU Rendering Attributes
+--> GPU Memory Transfer Commands
+--> GPU Other Commands
+--> GPU Display Control Commands (GP1)
+--> GPU Status Register
+--> GPU Versions
+--> GPU Depth Ordering
+--> GPU Video Memory (VRAM)
+--> GPU Texture Caching
+--> GPU Timings
+--> GPU (MISC)
+
+GPU I/O Ports, DMA Channels, Commands, VRAM
+-------------------------------------------
+
+GPU I/O Ports (1F801810h and 1F801814h in Read/Write Directions)
+ Port Name Expl.
+ 1F801810h-Write GP0 Send GP0 Commands/Packets (Rendering and VRAM Access)
+ 1F801814h-Write GP1 Send GP1 Commands (Display Control) (and DMA Control)
+ 1F801810h-Read GPUREAD Receive responses to GP0(C0h) and GP1(10h) commands
+ 1F801814h-Read GPUSTAT Receive GPU Status Register
+It (=GP0 only?) has a 64-byte (16-word) command FIFO buffer.
+Optionally, Port 1F801810h (Read/Write) can be also accessed via DMA2.
+
+GPU Timers / Synchronization
+Most of the Timers are bound to GPU timings, see
+--> Timers
+--> Interrupts
+
+GPU-related DMA Channels (DMA2 and DMA6)
+ Channel Recommended for
+ DMA2 in Linked Mode - Sending rendering commands ;GP0(20h..7Fh,E1h..E6h)
+ DMA2 in Continous Mode - VRAM transfers to/from GPU ;GP0(A0h,C0h)
+ DMA6 - Initializing the Link List ;Main RAM
+Note: Before using DMA2, set up the DMA Direction in GP1(04h).
+DMA2 is equivalent to accessing Port 1F801810h (GP0/GPUREAD) by software.
+DMA6 just initializes data in Main RAM (not physically connected to the GPU).
+
+GPU Command Summary
+Commands/Packets consist of a 8bit command number (MSBs) and a 24bit parameter
+(LSBs), which are written as 32bit value to GP0 or GP1.
+ GP0(00h) - Nop?
+ GP0(01h,02h,80h,A0h,C0h) - Direct VRAM Access
+ GP0(03h) - Unknown (does take up FIFO space!!!)
+ GP0(1Fh) - Interrupt Request (IRQ1)
+ GP0(20h..3Fh) - Render Polygons
+ GP0(40h..5Fh) - Render Lines
+ GP0(60h..7Fh) - Render Rectangles
+ GP0(E1h..E6h) - Rendering Attributes
+ GP1(00h..09h,10h,20h) - Display Control (these via GP1 register)
+Some GP0 commands require additional parameters, which are written (following
+to the command) as further 32bit values to GP0. The execution of the command
+starts when all parameters have been received (or, in case of Polygon/Line
+commands, when the first 3/2 vertices have been received).
+
+VRAM Overview / VRAM Addressing
+VRAM is 1MByte (not mapped to the CPU bus) (it can be read/written only via I/O
+or DMA). The memory is used for:
+ Framebuffer(s) ;Usually 2 buffers (Drawing Area, and Display Area)
+ Texture Page(s) ;Required when using Textures
+ Texture Palette(s) ;Required when using 4bit/8bit Textures
+The 1MByte VRAM is organized as 512 lines of 2048 bytes. It is accessed via
+coordinates, ranging from (0,0)=Upper-Left to (N,511)=Lower-Right.
+ Unit = 4bit 8bit 16bit 24bit Halfwords | Unit = Lines
+ Width = 4096 2048 1024 682.66 1024 | Height = 512
+The horizontal coordinates are addressing memory in
+4bit/8bit/16bit/24bit/halfword units (depending on what data formats you are
+using) (or a mixup thereof, eg. a halfword-base address, plus a 4bit texture
+coordinate).
+
+GPU Render Polygon Commands
+---------------------------
+
+GP0(20h) - Monochrome three-point polygon, opaque
+GP0(22h) - Monochrome three-point polygon, semi-transparent
+GP0(28h) - Monochrome four-point polygon, opaque
+GP0(2Ah) - Monochrome four-point polygon, semi-transparent
+ 1st Color+Command (CcBbGgRrh)
+ 2nd Vertex1 (YyyyXxxxh)
+ 3rd Vertex2 (YyyyXxxxh)
+ 4th Vertex3 (YyyyXxxxh)
+ (5th) Vertex4 (YyyyXxxxh) (if any)
+
+GP0(24h) - Textured three-point polygon, opaque, texture-blending
+GP0(25h) - Textured three-point polygon, opaque, raw-texture
+GP0(26h) - Textured three-point polygon, semi-transparent, texture-blending
+GP0(27h) - Textured three-point polygon, semi-transparent, raw-texture
+GP0(2Ch) - Textured four-point polygon, opaque, texture-blending
+GP0(2Dh) - Textured four-point polygon, opaque, raw-texture
+GP0(2Eh) - Textured four-point polygon, semi-transparent, texture-blending
+GP0(2Fh) - Textured four-point polygon, semi-transparent, raw-texture
+ 1st Color+Command (CcBbGgRrh) (color is ignored for raw-textures)
+ 2nd Vertex1 (YyyyXxxxh)
+ 3rd Texcoord1+Palette (ClutYyXxh)
+ 4th Vertex2 (YyyyXxxxh)
+ 5th Texcoord2+Texpage (PageYyXxh)
+ 6th Vertex3 (YyyyXxxxh)
+ 7th Texcoord3 (0000YyXxh)
+ (8th) Vertex4 (YyyyXxxxh) (if any)
+ (9th) Texcoord4 (0000YyXxh) (if any)
+
+GP0(30h) - Shaded three-point polygon, opaque
+GP0(32h) - Shaded three-point polygon, semi-transparent
+GP0(38h) - Shaded four-point polygon, opaque
+GP0(3Ah) - Shaded four-point polygon, semi-transparent
+ 1st Color1+Command (CcBbGgRrh)
+ 2nd Vertex1 (YyyyXxxxh)
+ 3rd Color2 (00BbGgRrh)
+ 4th Vertex2 (YyyyXxxxh)
+ 5th Color3 (00BbGgRrh)
+ 6th Vertex3 (YyyyXxxxh)
+ (7th) Color4 (00BbGgRrh) (if any)
+ (8th) Vertex4 (YyyyXxxxh) (if any)
+
+GP0(34h) - Shaded Textured three-point polygon, opaque, texture-blending
+GP0(36h) - Shaded Textured three-point polygon, semi-transparent, tex-blend
+GP0(3Ch) - Shaded Textured four-point polygon, opaque, texture-blending
+GP0(3Eh) - Shaded Textured four-point polygon, semi-transparent, tex-blend
+ 1st Color1+Command (CcBbGgRrh)
+ 2nd Vertex1 (YyyyXxxxh)
+ 3rd Texcoord1+Palette (ClutYyXxh)
+ 4th Color2 (00BbGgRrh)
+ 5th Vertex2 (YyyyXxxxh)
+ 6th Texcoord2+Texpage (PageYyXxh)
+ 7th Color3 (00BbGgRrh)
+ 8th Vertex3 (YyyyXxxxh)
+ 9th Texcoord3 (0000YyXxh)
+ (10th) Color4 (00BbGgRrh) (if any)
+ (11th) Vertex4 (YyyyXxxxh) (if any)
+ (12th) Texcoord4 (0000YyXxh) (if any)
+
+GP0(35h,37h,3Dh,3Fh) - Undocumented/Nonsense (Raw Texture + UNUSED shading)
+These are undocumented inefficient nonsense commands: Parameters are same as
+for GP0(34h,36h,3Ch,3Eh), ie. with colors for all vertices, but without
+actually using that colors. Instead, the commands are rendering raw textures
+without blending.
+In other words, the commands have same function as GP0(25h,27h,2Dh,2Fh), but
+with additional/unused parameters (and possible additional/unused internal
+gouraud shading calculations).
+For whatever reason, Castlevania is actually using these nonsense commands,
+namely GP0(3Dh) and GP0(3Fh).
+
+GP0(21h,23h,29h,2Bh,31h,33h,39h,3Bh) - Undocumented/Nonsense
+These commands have texture-blending disabled, which is nonsense because they
+are using untextured polygons anyways, ie. they are probably same as
+GP0(20h,22h,28h,2Ah,30h,32h,38h,3Ah).
+
+Notes
+Polygons are displayed up to <excluding> their lower-right coordinates.
+Four-point polygons are internally processed as two Three-point polygons, the
+first consisting of Vertices 1,2,3, and the second of Vertices 2,3,4.
+Within the Three-point polygons, the ordering of the vertices is don't care at
+the GPU side (a front-back check, based on clockwise or anti-clockwise
+ordering, can be implemented at the GTE side).
+Dither enable (in Texpage command) affects ONLY polygons that do use Gouraud
+Shading or Texture Blending.
+
+GPU Render Line Commands
+------------------------
+
+GP0(40h) - Monochrome line, opaque
+GP0(42h) - Monochrome line, semi-transparent
+GP0(48h) - Monochrome Poly-line, opaque
+GP0(4Ah) - Monochrome Poly-line, semi-transparent
+ 1st Color+Command (CcBbGgRrh)
+ 2nd Vertex1 (YyyyXxxxh)
+ 3rd Vertex2 (YyyyXxxxh)
+ (...) VertexN (YyyyXxxxh) (poly-line only)
+ (Last) Termination Code (55555555h) (poly-line only)
+
+GP0(50h) - Shaded line, opaque
+GP0(52h) - Shaded line, semi-transparent
+GP0(58h) - Shaded Poly-line, opaque
+GP0(5Ah) - Shaded Poly-line, semi-transparent
+ 1st Color1+Command (CcBbGgRrh)
+ 2nd Vertex1 (YyyyXxxxh)
+ 3rd Color2 (00BbGgRrh)
+ 4th Vertex2 (YyyyXxxxh)
+ (...) ColorN (00BbGgRrh) (poly-line only)
+ (...) VertexN (YyyyXxxxh) (poly-line only)
+ (Last) Termination Code (55555555h) (poly-line only)
+
+Note
+Lines are displayed up to <including> their lower-right coordinates (ie. unlike
+as for polygons, the lower-right coordinate is not excluded).
+If dithering is enabled (via Texpage command), then both monochrome and shaded
+lines are drawn with dithering (this differs from monochrome polygons and
+monochrome rectangles).
+
+Termination Codes for Poly-Lines (aka Linestrips)
+The termination code should be usually 55555555h, however, Wild Arms 2 uses
+50005000h (unknown which exact bits/values are relevant there).
+
+Wire-Frame
+Poly-Lines can be used (among others) to create Wire-Frame polygons (by setting
+the last Vertex equal to Vertex 1).
+
+GPU Render Rectangle Commands
+-----------------------------
+
+Rectangles are drawn much faster than polygons. Unlike for polygons, gouroud
+shading is not possible, dithering isn't applied, the rectangle must forcefully
+have horizontal and vertical edges, textures cannot be rotated or scaled, and,
+of course, the GPU does render Rectangles at once (without splitting them into
+triangles).
+
+GP0(60h) - Monochrome Rectangle (variable size) (opaque)
+GP0(62h) - Monochrome Rectangle (variable size) (semi-transparent)
+GP0(68h) - Monochrome Rectangle (1x1) (Dot) (opaque)
+GP0(6Ah) - Monochrome Rectangle (1x1) (Dot) (semi-transparent)
+GP0(70h) - Monochrome Rectangle (8x8) (opaque)
+GP0(72h) - Monochrome Rectangle (8x8) (semi-transparent)
+GP0(78h) - Monochrome Rectangle (16x16) (opaque)
+GP0(7Ah) - Monochrome Rectangle (16x16) (semi-transparent)
+ 1st Color+Command (CcBbGgRrh)
+ 2nd Vertex (YyyyXxxxh)
+ (3rd) Width+Height (YsizXsizh) (variable size only) (max 1023x511)
+
+GP0(64h) - Textured Rectangle, variable size, opaque, texture-blending
+GP0(65h) - Textured Rectangle, variable size, opaque, raw-texture
+GP0(66h) - Textured Rectangle, variable size, semi-transp, texture-blending
+GP0(67h) - Textured Rectangle, variable size, semi-transp, raw-texture
+GP0(6Ch) - Textured Rectangle, 1x1 (nonsense), opaque, texture-blending
+GP0(6Dh) - Textured Rectangle, 1x1 (nonsense), opaque, raw-texture
+GP0(6Eh) - Textured Rectangle, 1x1 (nonsense), semi-transp, texture-blending
+GP0(6Fh) - Textured Rectangle, 1x1 (nonsense), semi-transp, raw-texture
+GP0(74h) - Textured Rectangle, 8x8, opaque, texture-blending
+GP0(75h) - Textured Rectangle, 8x8, opaque, raw-texture
+GP0(76h) - Textured Rectangle, 8x8, semi-transparent, texture-blending
+GP0(77h) - Textured Rectangle, 8x8, semi-transparent, raw-texture
+GP0(7Ch) - Textured Rectangle, 16x16, opaque, texture-blending
+GP0(7Dh) - Textured Rectangle, 16x16, opaque, raw-texture
+GP0(7Eh) - Textured Rectangle, 16x16, semi-transparent, texture-blending
+GP0(7Fh) - Textured Rectangle, 16x16, semi-transparent, raw-texture
+ 1st Color+Command (CcBbGgRrh) (color is ignored for raw-textures)
+ 2nd Vertex (YyyyXxxxh) (upper-left edge of the rectangle)
+ 3rd Texcoord+Palette (ClutYyXxh) (for 4bpp Textures Xxh must be even!)
+ (4th) Width+Height (YsizXsizh) (variable size only) (max 1023x511)
+Unlike for Textured-Polygons, the "Texpage" must be set up separately for
+Rectangles, via GP0(E1h). Width and Height can be up to 1023x511, however, the
+maximum size of the texture window is 256x256 (so the source data will be
+repeated when trying to use sizes larger than 256x256).
+
+Texture Origin and X/Y-Flip
+Vertex & Texcoord specify the upper-left edge of the rectangle. And, normally,
+screen coords and texture coords are both incremented during rendering the
+rectangle pixels.
+Optionally, X/Y-Flip bits can be set in Texpage.Bit12/13, these bits cause the
+texture coordinates to be decremented (instead of incremented). The X/Y-Flip
+bits do affect only Rectangles (not Polygons, nor VRAM Transfers).
+Caution: Reportedly, the X/Y-Flip feature isn't supported on old PSX consoles
+(unknown which ones exactly, maybe such with PU-7 mainboards, and unknown how
+to detect flipping support; except of course by reading VRAM).
+
+Note
+There are also two VRAM Transfer commands which work similar to GP0(60h) and
+GP0(65h). Eventually, that commands might be even faster... although not sure
+if they do use the Texture Cache?
+The difference is that VRAM Transfers do not clip to the Drawig Area boundary,
+do not support fully-transparent nor semi-transparent texture pixels, and do
+not convert color depths (eg. without 4bit texture to 16bit framebuffer
+conversion).
+
+GPU Rendering Attributes
+------------------------
+
+Vertex (Parameter for Polygon, Line, Rectangle commands)
+ 0-10 X-coordinate (signed, -1024..+1023)
+ 11-15 Not used (usually sign-extension, but ignored by hardware)
+ 16-26 Y-coordinate (signed, -1024..+1023)
+ 26-31 Not used (usually sign-extension, but ignored by hardware)
+Size Restriction: The maximum distance between two vertices is 1023
+horizontally, and 511 vertically. Polygons and lines that are exceeding that
+dimensions are NOT rendered. For example, a line from Y1=-300 to Y2=+300 is NOT
+rendered, a line from Y1=-100 to Y2=+400 is rendered (as far as it is within
+the drawing area).
+If portions of the polygon/line/rectangle are located outside of the drawing
+area, then the hardware renders only the portion that is inside of the drawing
+area. Not sure if the hardware is skipping all clipped pixels at once (within a
+single clock cycle), or if it's (slowly) processing them pixel by pixel?
+
+Color Attribute (Parameter for all Rendering commands, except Raw Texture)
+ 0-7 Red (0..FFh)
+ 8-15 Green (0..FFh)
+ 16-23 Blue (0..FFh)
+ 24-31 Command (in first paramter) (don't care in further parameters)
+Caution: For untextured graphics, 8bit RGB values of FFh are brightest.
+However, for texture blending, 8bit values of 80h are brightest (values
+81h..FFh are "brighter than bright" allowing to make textures about twice as
+bright as than they were originially stored in memory; of course the results
+can't exceed the maximum brightness, ie. the 5bit values written to the
+framebuffer are saturated to max 1Fh).
+
+Texpage Attribute (Parameter for Textured-Polygons commands)
+ 0-8 Same as GP0(E1h).Bit0-8 (see there)
+ 9-10 Unused (does NOT change GP0(E1h).Bit9-10)
+ 11 Same as GP0(E1h).Bit11 (see there)
+ 12-13 Unused (does NOT change GP0(E1h).Bit12-13)
+ 14-15 Unused (should be 0)
+This attribute is used in all Textured-Polygons commands.
+
+Clut Attribute (Color Lookup Table, aka Palette)
+This attribute is used in all Textured Polygon/Rectangle commands. Of course,
+it's relevant only for 4bit/8bit textures (don't care for 15bit textures).
+ 0-5 X coordinate X/16 (ie. in 16-halfword steps)
+ 6-14 Y coordinate 0-511 (ie. in 1-line steps)
+ 15 Unknown/unused (should be 0)
+Specifies the location of the CLUT data within VRAM.
+
+GP0(E1h) - Draw Mode setting (aka "Texpage")
+ 0-3 Texture page X Base (N*64) (ie. in 64-halfword steps) ;GPUSTAT.0-3
+ 4 Texture page Y Base (N*256) (ie. 0 or 256) ;GPUSTAT.4
+ 5-6 Semi Transparency (0=B/2+F/2, 1=B+F, 2=B-F, 3=B+F/4) ;GPUSTAT.5-6
+ 7-8 Texture page colors (0=4bit, 1=8bit, 2=15bit, 3=Reserved);GPUSTAT.7-8
+ 9 Dither 24bit to 15bit (0=Off/strip LSBs, 1=Dither Enabled) ;GPUSTAT.9
+ 10 Drawing to display area (0=Prohibited, 1=Allowed) ;GPUSTAT.10
+ 11 Texture Disable (0=Normal, 1=Disable if GP1(09h).Bit0=1) ;GPUSTAT.15
+ (Above might be chipselect for (absent) second VRAM chip?)
+ 12 Textured Rectangle X-Flip (BIOS does set this bit on power-up...?)
+ 13 Textured Rectangle Y-Flip (BIOS does set it equal to GPUSTAT.13...?)
+ 14-23 Not used (should be 0)
+ 24-31 Command (E1h)
+The GP0(E1h) command is required only for Lines, Rectangle, and
+Untextured-Polygons (for Textured-Polygons, the data is specified in form of
+the Texpage attribute; except that, Bit9-10 can be changed only via GP0(E1h),
+not via the Texpage attribute).
+Texture page colors setting 3 (reserved) is same as setting 2 (15bit).
+Note: GP0(00h) seems to be often inserted between Texpage and Rectangle
+commands, maybe it acts as a NOP, which may be required between that commands,
+for timing reasons...?
+
+GP0(E2h) - Texture Window setting
+ 0-4 Texture window Mask X (in 8 pixel steps)
+ 5-9 Texture window Mask Y (in 8 pixel steps)
+ 10-14 Texture window Offset X (in 8 pixel steps)
+ 15-19 Texture window Offset Y (in 8 pixel steps)
+ 20-23 Not used (zero)
+ 24-31 Command (E2h)
+Mask specifies the bits that are to be manipulated, and Offset contains the new
+values for these bits, ie. texture X/Y coordinates are adjusted as so:
+ Texcoord = (Texcoord AND (NOT (Mask*8))) OR ((Offset AND Mask)*8)
+The area within a texture window is repeated throughout the texture page. The
+data is not actually stored all over the texture page but the GPU reads the
+repeated patterns as if they were there.
+
+GP0(E3h) - Set Drawing Area top left (X1,Y1)
+GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
+ 0-9 X-coordinate (0..1023)
+ 10-18 Y-coordinate (0..511) ;\on Old 160pin GPU (max 1MB VRAM)
+ 19-23 Not used (zero) ;/
+ 10-19 Y-coordinate (0..1023) ;\on New 208pin GPU (max 2MB VRAM)
+ 20-23 Not used (zero) ;/(retail consoles have only 1MB though)
+ 24-31 Command (Exh)
+Sets the drawing area corners. The Render commands GP0(20h..7Fh) are
+automatically clipping any pixels that are outside of this region.
+
+GP0(E5h) - Set Drawing Offset (X,Y)
+ 0-10 X-offset (-1024..+1023) (usually within X1,X2 of Drawing Area)
+ 11-21 Y-offset (-1024..+1023) (usually within Y1,Y2 of Drawing Area)
+ 22-23 Not used (zero)
+ 24-31 Command (E5h)
+If you have configured the GTE to produce vertices with coordinate "0,0" being
+located in the center of the drawing area, then the Drawing Offset must be
+"X1+(X2-X1)/2, Y1+(Y2-Y1)/2". Or, if coordinate "0,0" shall be the upper-left
+of the Drawing Area, then Drawing Offset should be "X1,Y1". Where X1,Y1,X2,Y2
+are the values defined with GP0(E3h-E4h).
+
+GP0(E6h) - Mask Bit Setting
+ 0 Set mask while drawing (0=TextureBit15, 1=ForceBit15=1) ;GPUSTAT.11
+ 1 Check mask before draw (0=Draw Always, 1=Draw if Bit15=0) ;GPUSTAT.12
+ 2-23 Not used (zero)
+ 24-31 Command (E6h)
+When bit0 is off, the upper bit of the data written to the framebuffer is equal
+to bit15 of the texture color (ie. it is set for colors that are marked as
+"semi-transparent") (for untextured polygons, bit15 is set to zero).
+When bit1 is on, any (old) pixels in the framebuffer with bit15=1 are
+write-protected, and cannot be overwritten by (new) rendering commands.
+The mask setting affects all rendering commands, as well as CPU-to-VRAM and
+VRAM-to-VRAM transfer commands (where it acts on the separate halfwords, ie. as
+for 15bit textures). However, Mask does NOT affect the Fill-VRAM command.
+
+Note
+GP0(E3h..E5h) do not take up space in the FIFO, so they are probably executed
+immediately (even if there're still other commands in the FIFO). Best use them
+only if you are sure that the FIFO is empty (otherwise the new Drawing Area
+settings might accidently affect older Rendering Commands in the FIFO).
+
+GPU Memory Transfer Commands
+----------------------------
+
+GP0(01h) - Clear Cache
+ 1st Command (Cc000000h)
+"Seems to be the same as the GP1 command." Uh, which GP1 command?
+Before using GP(A0h) or GP(C0h) one should reportedly send:
+Clear Cache (01000000h)
+"Reset command buffer (write to GP1 or GP0)" Uh? Bullshit.
+However, there <may> be some situations in which it is neccessary to flush the
+texture cache.
+
+GP0(02h) - Fill Rectangle in VRAM
+ 1st Color+Command (CcBbGgRrh) ;24bit RGB value (see note)
+ 2nd Top Left Corner (YyyyXxxxh) ;Xpos counted in halfwords, steps of 10h
+ 3rd Width+Height (YsizXsizh) ;Xsiz counted in halfwords, steps of 10h
+Fills the area in the frame buffer with the value in RGB. Horizontally the
+filling is done in 16-pixel (32-bytes) units (see below masking/rounding).
+The "Color" parameter is a 24bit RGB value, however, the actual fill data is
+16bit: The hardware automatically converts the 24bit RGB value to 15bit RGB
+(with bit15=0).
+Fill is NOT affected by the Mask settings (acts as if Mask.Bit0,1 are both
+zero).
+
+GP0(80h) - Copy Rectangle (VRAM to VRAM)
+ 1st Command (Cc000000h)
+ 2nd Source Coord (YyyyXxxxh) ;Xpos counted in halfwords
+ 3rd Destination Coord (YyyyXxxxh) ;Xpos counted in halfwords
+ 4th Width+Height (YsizXsizh) ;Xsiz counted in halfwords
+Copys data within framebuffer. The transfer is affected by Mask setting.
+
+GP0(A0h) - Copy Rectangle (CPU to VRAM)
+ 1st Command (Cc000000h)
+ 2nd Destination Coord (YyyyXxxxh) ;Xpos counted in halfwords
+ 3rd Width+Height (YsizXsizh) ;Xsiz counted in halfwords
+ ... Data (...) <--- usually transferred via DMA
+Transfers data from CPU to frame buffer. If the number of halfwords to be sent
+is odd, an extra halfword should be sent (packets consist of 32bit units). The
+transfer is affected by Mask setting.
+
+GP0(C0h) - Copy Rectangle (VRAM to CPU)
+ 1st Command (Cc000000h) ;\
+ 2nd Source Coord (YyyyXxxxh) ; write to GP0 port (as usually)
+ 3rd Width+Height (YsizXsizh) ;/
+ ... Data (...) ;<--- read from GPUREAD port (or via DMA)
+Transfers data from frame buffer to CPU. Wait for bit27 of the status register
+to be set before reading the image data. When the number of halfwords is odd,
+an extra halfword is read at the end (packets consist of 32bit units).
+
+Masking and Rounding for FILL Command parameters
+ Xpos=(Xpos AND 3F0h) ;range 0..3F0h, in steps of 10h
+ Ypos=(Ypos AND 1FFh) ;range 0..1FFh
+ Xsiz=((Xsiz AND 3FFh)+0Fh) AND (NOT 0Fh) ;range 0..400h, in steps of 10h
+ Ysiz=((Ysiz AND 1FFh)) ;range 0..1FFh
+Fill does NOT occur when Xsiz=0 or Ysiz=0 (unlike as for Copy commands).
+Xsiz=400h works only indirectly: Param=400h is handled as Xsiz=0, however,
+Param=3F1h..3FFh is rounded-up and handled as Xsiz=400h.
+
+Masking for COPY Commands parameters
+ Xpos=(Xpos AND 3FFh) ;range 0..3FFh
+ Ypos=(Ypos AND 1FFh) ;range 0..1FFh
+ Xsiz=((Xsiz-1) AND 3FFh)+1 ;range 1..400h
+ Ysiz=((Ysiz-1) AND 1FFh)+1 ;range 1..200h
+Parameters are just clipped to 10bit/9bit range, the only special case is that
+Size=0 is handled as Size=max.
+
+Notes
+The coordinates for the above VRAM transfer commands are absolute framebuffer
+addresses (not relative to Draw Offset, and not clipped to Draw Area).
+Non-DMA transfers seem to be working at any time, but GPU-DMA Transfers seem to
+be working ONLY during V-Blank (outside of V-Blank, portions of the data appear
+to be skipped, and the following words arrive at wrong addresses), unknown if
+it's possible to change that by whatever configuration settings...? That
+problem appears ONLY for continous DMA aka VRAM transfers (linked-list DMA aka
+Ordering Table works even outside V-Blank).
+
+Wrapping
+If the Source/Dest starting points plus the width/height value exceed the
+1024x512 pixel VRAM size, then the Copy/Fill operations wrap to the opposite
+memory edge (without any carry-out from X to Y, nor from Y to X).
+
+GPU Other Commands
+------------------
+
+GP0(1Fh) - Interrupt Request (IRQ1)
+ 1st Command (Cc000000h) ;GPUSTAT.24
+Requests IRQ1. Can be acknowledged via GP1(02h). This feature is rarely used.
+Note: The command is used by Blaze'n'Blade, but the game doesn't have IRQ1
+enabled, and the written value (1F801810h) looks more like an I/O address,
+rather than like a command, so not sure if it's done intentionally, or if it is
+just a bug.
+
+GP0(03h) - Unknown?
+Unknown. Doesn't seem to be used by any games. Unlike the "NOP" commands,
+GP0(03h) does take up space in FIFO, so it is apparently not a NOP.
+
+GP0(00h) - NOP (?)
+This command doesn't take up space in the FIFO (eg. even if a VRAM-to-VRAM
+transfer is still busy, one can send dozens of GP0(00h) commands, without the
+command FIFO becoming full. So, either the command is ignored (or, if it has a
+function, it is executed immediately, even while the transfer is busy).
+...
+GP0(00h) unknown, used with parameter = 08A16Ch... or rather 08FDBCh ... the
+written value seems to be a bios/ram memory address, anded with 00FFFFFFh...
+maybe a bios bug?
+GP0(00h) seems to be often inserted between Texpage and Rectangle commands,
+maybe it acts as a NOP, which may be required between that commands, for timing
+reasons...?
+
+GP0(04h..1Eh,E0h,E7h..EFh) - Mirrors of GP0(00h) - NOP (?)
+Like GP0(00h), these commands don't take up space in the FIFO. So, maybe, they
+are same as GP0(00h), however, the Drawing Area/Offset commands GP0(E3h..E5h)
+don't take up FIFO space either, so not taking up FIFO space doesn't
+neccessarily mean that the command has no function.
+
+GP0(81h..9Fh) - Mirror of GP0(80h) - Copy Rectangle (VRAM to VRAM)
+GP0(A1h..BFh) - Mirror of GP0(A0h) - Copy Rectangle (CPU to VRAM)
+GP0(C1h..DFh) - Mirror of GP0(C0h) - Copy Rectangle (VRAM to CPU)
+Mirrors.
+
+GPU Display Control Commands (GP1)
+----------------------------------
+
+GP1 Display Control Commands are sent by writing the 8bit Command number
+(MSBs), and 24bit parameter (LSBs) to Port 1F801814h. Unlike GP0 commands, GP1
+commands are passed directly to the GPU (ie. they can be sent even when the
+FIFO is full).
+
+GP1(00h) - Reset GPU
+ 0-23 Not used (zero)
+Resets the GPU to the following values:
+ GP1(01h) ;clear fifo
+ GP1(02h) ;ack irq (0)
+ GP1(03h) ;display off (1)
+ GP1(04h) ;dma off (0)
+ GP1(05h) ;display address (0)
+ GP1(06h) ;display x1,x2 (x1=200h, x2=200h+256*10)
+ GP1(07h) ;display y1,y2 (y1=010h, y2=010h+240)
+ GP1(08h) ;display mode 320x200 NTSC (0)
+ GP0(E1h..E6h) ;rendering attributes (0)
+Accordingly, GPUSTAT becomes 14802000h. The x1,y1 values are too small, ie. the
+upper-left edge isn't visible. Note that GP1(09h) is NOT affected by the reset
+command.
+
+GP1(01h) - Reset Command Buffer
+ 0-23 Not used (zero)
+Resets the command buffer.
+
+GP1(02h) - Acknowledge GPU Interrupt (IRQ1)
+ 0-23 Not used (zero) ;GPUSTAT.24
+Resets the IRQ flag in GPUSTAT.24. The flag can be set via GP0(1Fh).
+
+GP1(03h) - Display Enable
+ 0 Display On/Off (0=On, 1=Off) ;GPUSTAT.23
+ 1-23 Not used (zero)
+Turns display on/off. "Note that a turned off screen still gives the flicker of
+NTSC on a PAL screen if NTSC mode is selected."
+The "Off" settings displays a black picture (and still sends /SYNC signals to
+the television set). (Unknown if it still generates vblank IRQs though?)
+
+GP1(04h) - DMA Direction / Data Request
+ 0-1 DMA Direction (0=Off, 1=FIFO, 2=CPUtoGP0, 3=GPUREADtoCPU) ;GPUSTAT.29-30
+ 2-23 Not used (zero)
+Notes: Manually sending/reading data by software (non-DMA) is ALWAYS possible,
+regardless of the GP1(04h) setting. The GP1(04h) setting does affect the
+meaning of GPUSTAT.25.
+
+Display start/end
+Specifies where the display area is positioned on the screen, and how much data
+gets sent to the screen. The screen sizes of the display area are valid only if
+the horizontal/vertical start/end values are default. By changing these you can
+get bigger/smaller display screens. On most TV's there is some black around the
+edge, which can be utilised by setting the start of the screen earlier and the
+end later. The size of the pixels is NOT changed with these settings, the GPU
+simply sends more data to the screen. Some monitors/TVs have a smaller display
+area and the extended size might not be visible on those sets. "(Mine is
+capable of about 330 pixels horizontal, and 272 vertical in 320*240 mode)"
+
+GP1(05h) - Start of Display area (in VRAM)
+ 0-9 X (0-1023) (halfword address in VRAM) (relative to begin of VRAM)
+ 10-18 Y (0-511) (scanline number in VRAM) (relative to begin of VRAM)
+ 19-23 Not used (zero)
+Upper/left Display source address in VRAM. The size and target position on
+screen is set via Display Range registers; target=X1,Y2;
+size=(X2-X1/cycles_per_pix), (Y2-Y1).
+
+GP1(06h) - Horizontal Display range (on Screen)
+ 0-11 X1 (260h+0) ;12bit ;\counted in 53.222400MHz units,
+ 12-23 X2 (260h+320*8) ;12bit ;/relative to HSYNC
+Specifies the horizontal range within which the display area is displayed. For
+resolutions other than 320 pixels it may be necessary to fine adjust the value
+to obtain an exact match (eg. X2=X1+pixels*cycles_per_pix).
+The number of displayed pixels per line is "(((X2-X1)/cycles_per_pix)+2) AND
+NOT 3" (ie. the hardware is rounding the width up/down to a multiple of 4
+pixels).
+Most games are using a width equal to the horizontal resolution (ie. 256, 320,
+368, 512, 640 pixels). A few games are using slightly smaller widths (probably
+due to programming bugs). Pandemonium 2 is using a bigger "overscan" width
+(ensuring an intact picture without borders even on mis-calibrated TV sets).
+The 260h value is the first visible pixel on normal TV Sets, this value is used
+by MOST NTSC games, and SOME PAL games (see below notes on Mis-Centered PAL
+games).
+
+GP1(07h) - Vertical Display range (on Screen)
+ 0-9 Y1 (NTSC=88h-(224/2), (PAL=A3h-(264/2)) ;\scanline numbers on screen,
+ 10-19 Y2 (NTSC=88h+(224/2), (PAL=A3h+(264/2)) ;/relative to VSYNC
+ 20-23 Not used (zero)
+Specifies the vertical range within which the display area is displayed. The
+number of lines is Y2-Y1 (unlike as for the width, there's no rounding applied
+to the height). If Y2 is set to a much too large value, then the hardware stops
+to generate vblank interrupts (IRQ0).
+The 88h/A3h values are the middle-scanlines on normal TV Sets, these values are
+used by MOST NTSC games, and SOME PAL games (see below notes on Mis-Centered
+PAL games).
+The 224/264 values are for fullscreen pictures. Many NTSC games display 240
+lines (overscan with hidden lines). Many PAL games display only 256 lines
+(underscan with black borders).
+
+GP1(08h) - Display mode
+ 0-1 Horizontal Resolution 1 (0=256, 1=320, 2=512, 3=640) ;GPUSTAT.17-18
+ 2 Vertical Resolution (0=240, 1=480, when Bit5=1) ;GPUSTAT.19
+ 3 Video Mode (0=NTSC/60Hz, 1=PAL/50Hz) ;GPUSTAT.20
+ 4 Display Area Color Depth (0=15bit, 1=24bit) ;GPUSTAT.21
+ 5 Vertical Interlace (0=Off, 1=On) ;GPUSTAT.22
+ 6 Horizontal Resolution 2 (0=256/320/512/640, 1=368) ;GPUSTAT.16
+ 7 "Reverseflag" (0=Normal, 1=Distorted) ;GPUSTAT.14
+ 8-23 Not used (zero)
+Note: Interlace must be enabled to see all lines in 480-lines mode (interlace
+is causing ugly flickering, so a non-interlaced low resolution image is
+typically having better quality than a high resolution interlaced image, a
+pretty bad example are the intro screens shown by the BIOS). The Display Area
+Color Depth does NOT affect the Drawing Area (the Drawing Area is <always>
+15bit).
+When the "Reverseflag" is set, the display scrolls down 2 lines or so, and
+colored regions are getting somehow hatched/distorted, but black and white
+regions are still looking okay. Don't know what that's good for? Probably
+relates to PAL/NTSC-Color Clock vs PSX-Dot Clock mismatches: Bit7=0 causes
+Flimmering errors (errors at different locations in each frame), and Bit7=1
+causes Static errors (errors at same locations in all frames)?
+
+GP1(10h) - Get GPU Info
+GP1(11h..1Fh) - Mirrors of GP1(10h), Get GPU Info
+After sending the command, the result can be immediately read from GPUREAD
+register (there's no NOP or other delay required) (namely GPUSTAT.Bit27 is used
+only for VRAM-Reads, but NOT for GPU-Info-Reads, so do not try to wait for that
+flag).
+ 0-23 Select Information which is to be retrieved (via following GPUREAD)
+On Old 180pin GPUs, following values can be selected:
+ 00h-01h = Returns Nothing (old value in GPUREAD remains unchanged)
+ 02h = Read Texture Window setting ;GP0(E2h) ;20bit/MSBs=Nothing
+ 03h = Read Draw area top left ;GP0(E3h) ;19bit/MSBs=Nothing
+ 04h = Read Draw area bottom right ;GP0(E4h) ;19bit/MSBs=Nothing
+ 05h = Read Draw offset ;GP0(E5h) ;22bit
+ 06h-07h = Returns Nothing (old value in GPUREAD remains unchanged)
+ 08h-FFFFFFh = Mirrors of 00h..07h
+On New 208pin GPUs, following values can be selected:
+ 00h-01h = Returns Nothing (old value in GPUREAD remains unchanged)
+ 02h = Read Texture Window setting ;GP0(E2h) ;20bit/MSBs=Nothing
+ 03h = Read Draw area top left ;GP0(E3h) ;20bit/MSBs=Nothing
+ 04h = Read Draw area bottom right ;GP0(E4h) ;20bit/MSBs=Nothing
+ 05h = Read Draw offset ;GP0(E5h) ;22bit
+ 06h = Returns Nothing (old value in GPUREAD remains unchanged)
+ 07h = Read GPU Type (usually 2) ;see "GPU Versions" chapter
+ 08h = Unknown (Returns 00000000h) (lightgun on some GPUs?)
+ 09h-0Fh = Returns Nothing (old value in GPUREAD remains unchanged)
+ 10h-FFFFFFh = Mirrors of 00h..0Fh
+The selected data is latched in GPUREAD, the same/latched value can be read
+multiple times, but, the latch isn't automatically updated when changing GP0
+registers.
+
+GP1(09h) - New Texture Disable
+ 0 Texture Disable (0=Normal, 1=Allow Disable via GP0(E1h).11) ;GPUSTAT.15
+ 1-23 Unknown (seems to have no effect)
+This feature seems to be intended for debugging purposes (most released games
+do contain program code for disabling textures, but do never execute it).
+GP1(09h) seems to be supported only on New GPUs. Old GPUs don't support it all,
+and there seem to be some Special/Prototype GPUs that use GP1(20h) instead of
+GP1(09h).
+
+GP1(20h) - Special/Prototype Texture Disable
+ 0-23 Unknown (501h=Texture Enable, 504h=Texture Disable, or so?)
+Seems to be a used only on whatever arcade/prototype GPUs. New GPUs are using
+GP1(09h) instead of GP1(20h).
+
+GP1(0Bh) - Unknown/Internal?
+ 0-10 Unknown (GPU crashes after a while when set to 274h..7FFh)
+ 11-23 Unknown (seems to have no effect)
+The register doesn't seem to be used by any games.
+
+GP1(0Ah,0Ch..0Fh,21h..3Fh) - N/A
+Not used?
+
+GP1(40h..FFh) - N/A (Mirrors)
+Mirrors of GP1(00h..3Fh).
+
+Mis-Centered PAL Games (wrong GP1(06h)/GP1(07h) settings)
+NTSC games are typically well centered (using X1=260h, and Y1/Y2=88h+/-N).
+PAL games should be centered as X1=260h, and Y1/Y2=A3h+/-N) - these values
+would be looking well on a Philips Philetta TV Set, and do also match up with
+other common picture positions (eg. as used by Nintendo's SNES console).
+However, most PAL games are using completely different "random" centering
+values (maybe caused by different developers trying to match the centering to
+the different TV Sets) (although it looks more as if the PAL developers just
+went amok: Many PAL games are even using different centerings for their Intro,
+Movie, and actual Game sequences).
+In result, most PAL games are looking like crap when playing them on a real
+PSX. For PSX emulators it may be recommended to ignore the GP1(06h)/GP1(07h)
+centering, and instead, apply auto-centering to PAL games.
+For PAL game developers, it may be recommended to add a screen centering option
+(as found in Tomb Raider 3, for example). Unknown if this is really required...
+or if X1=260h, and Y1/Y2=A3h+/-N would work fine on most or all PAL TV Sets?
+
+GPU Status Register
+-------------------
+
+1F801814h - GPUSTAT - GPU Status Register (R)
+ 0-3 Texture page X Base (N*64) ;GP0(E1h).0-3
+ 4 Texture page Y Base (N*256) (ie. 0 or 256) ;GP0(E1h).4
+ 5-6 Semi Transparency (0=B/2+F/2, 1=B+F, 2=B-F, 3=B+F/4) ;GP0(E1h).5-6
+ 7-8 Texture page colors (0=4bit, 1=8bit, 2=15bit, 3=Reserved)GP0(E1h).7-8
+ 9 Dither 24bit to 15bit (0=Off/strip LSBs, 1=Dither Enabled);GP0(E1h).9
+ 10 Drawing to display area (0=Prohibited, 1=Allowed) ;GP0(E1h).10
+ 11 Set Mask-bit when drawing pixels (0=No, 1=Yes/Mask) ;GP0(E6h).0
+ 12 Draw Pixels (0=Always, 1=Not to Masked areas) ;GP0(E6h).1
+ 13 Interlace Field (or, always 1 when GP1(08h).5=0)
+ 14 "Reverseflag" (0=Normal, 1=Distorted) ;GP1(08h).7
+ 15 Texture Disable (0=Normal, 1=Disable Textures) ;GP0(E1h).11
+ 16 Horizontal Resolution 2 (0=256/320/512/640, 1=368) ;GP1(08h).6
+ 17-18 Horizontal Resolution 1 (0=256, 1=320, 2=512, 3=640) ;GP1(08h).0-1
+ 19 Vertical Resolution (0=240, 1=480, when Bit22=1) ;GP1(08h).2
+ 20 Video Mode (0=NTSC/60Hz, 1=PAL/50Hz) ;GP1(08h).3
+ 21 Display Area Color Depth (0=15bit, 1=24bit) ;GP1(08h).4
+ 22 Vertical Interlace (0=Off, 1=On) ;GP1(08h).5
+ 23 Display Enable (0=Enabled, 1=Disabled) ;GP1(03h).0
+ 24 Interrupt Request (IRQ1) (0=Off, 1=IRQ) ;GP0(1Fh)/GP1(02h)
+ 25 DMA / Data Request, meaning depends on GP1(04h) DMA Direction:
+ When GP1(04h)=0 ---> Always zero (0)
+ When GP1(04h)=1 ---> FIFO State (0=Full, 1=Not Full)
+ When GP1(04h)=2 ---> Same as GPUSTAT.28
+ When GP1(04h)=3 ---> Same as GPUSTAT.27
+ 26 Ready to receive Cmd Word (0=No, 1=Ready) ;GP0(...) ;via GP0
+ 27 Ready to send VRAM to CPU (0=No, 1=Ready) ;GP0(C0h) ;via GPUREAD
+ 28 Ready to receive DMA Block (0=No, 1=Ready) ;GP0(...) ;via GP0
+ 29-30 DMA Direction (0=Off, 1=?, 2=CPUtoGP0, 3=GPUREADtoCPU) ;GP1(04h).0-1
+ 31 Drawing even/odd lines in interlace mode (0=Even or Vblank, 1=Odd)
+In 480-lines mode, bit31 changes per frame. And in 240-lines mode, the bit
+changes per scanline. The bit is always zero during Vblank (vertical retrace
+and upper/lower screen border).
+
+Note
+Further GPU status information can be retrieved via GP1(10h) and GP0(C0h).
+
+Ready Bits
+Bit28: Normally, this bit gets cleared when the command execution is busy (ie.
+once when the command and all of its parameters are received), however, for
+Polygon and Line Rendering commands, the bit gets cleared immediately after
+receiving the command word (ie. before receiving the vertex parameters). The
+bit is used as DMA request in DMA Mode 2, accordingly, the DMA would probably
+hang if the Polygon/Line parameters are transferred in a separate DMA block
+(ie. the DMA probably starts ONLY on command words).
+Bit27: Gets set after sending GP0(C0h) and its parameters, and stays set until
+all data words are received; used as DMA request in DMA Mode 3.
+Bit26: Gets set when the GPU wants to receive a command. If the bit is cleared,
+then the GPU does either want to receive data, or it is busy with a command
+execution (and doesn't want to receive anything).
+Bit25: This is the DMA Request bit, however, the bit is also useful for non-DMA
+transfers, especially in the FIFO State mode.
+
+GPU Versions
+------------
+
+Summary of GPU Differences
+ Differences... Old 160pin GPU New 208pin GPU
+ GPU Chip CXD8514Q CXD8561Q/BQ/CQ/CXD9500Q
+ Mainboard EARLY-PU-8 and below LATE-PU-8 and up
+ Memory Type Dual-ported VRAM Normal DRAM
+ GPUSTAT.13 when interlace=off always 0 always 1
+ GPUSTAT.14 always 0 reverseflag
+ GPUSTAT.15 always 0 texture_disable
+ GP1(10h:index3..4) 19bit (1MB VRAM) 20bit (2MB VRAM)
+ GP1(10h:index7) N/A 00000002h version
+ GP1(10h:index8) mirror of index0 00000000h zero
+ GP1(10h:index9..F) mirror of index1..7 N/A
+ GP1(20h) whatever? used for detecting old gpu
+ GP0(E1h).bit12/13 without x/y-flip with x/y-flip
+ GP0(03h) N/A (no stored in fifo) unknown/unused command
+ Shaded Textures ((color/8)*texel)/2 (color*texel)/16
+ GP0(02h) FillVram xpos.bit0-3=0Fh=bugged xpos.bit0-3=ignored
+ dma-to-vram: doesn't work with blksiz>10h (new gpu works with blksiz=8C0h!)
+ dma-to-vram: MAYBE also needs extra software-handshake to confirm DMA done?
+ 320*224 pix = 11800h pix = 8C00h words
+ GP0(80h) VramToVram works Freeze on large moves?
+
+Shaded Textures
+The Old GPU crops 8:8:8 bit gouraud shading color to 5:5:5 bit before
+multiplying it with the texture color, resulting in rather poor graphics. For
+example, the snow scence in the first level of Tomb Raider I looks a lot
+smoother on New GPUs.
+The cropped colors are looking a bit as if dithering would be disabled
+(although, technically dithering works fine, but due to the crippled color
+input, it's always using the same dither pattern per 8 intensities, instead of
+using 8 different dither patterns).
+
+Memory/Rendering Timings
+The Old GPU uses two Dual-ported VRAM chips (each with two 16bit databusses,
+one for CPU/DMA/rendering access, and one for output to the video DAC). The New
+GPU uses s normal DRAM chip (with single 32bit databus).
+The exact timing differences are unknown, but the different memory types should
+result in quite different timings:
+The Old GPU might perform better on non-32bit aligned accesses, and on memory
+accesses performed simultaneously with DAC output.
+On the other hand, the New GPU's DRAM seems to be faster in some cases (for
+example, during Vblank, it's fast enough to perform DMA's with blksiz>10h,
+which exceeds the GPU's FIFO size, and causes lost data on Old GPUs).
+
+X/Y-Flip and 2MB Video RAM
+The X/Y-flipping feature may be used by arcade games (provided that the arcade
+board is fitted with New GPUs). The flipping feature does also work on retail
+consoles with New GPUs, but PSX games should never use that feature (for
+maintaining compatiblity with older PSX consoles).
+2Mbyte Video RAM is used on some arcade boards. Whilst PSX retail consoles are
+always containing only 1MByte RAM, so the feature cannot be used even if the
+console contains a New GPU. There's one special case: Some PSone consoles are
+actually fitted with 2MB chips (maybe because smaller chips haven't been in
+production anymore), but the chips are wired so that only half of the memory is
+accessible (the extra memory could be theoretically unlocked with some minimal
+hardware modification).
+
+GPU Detection (and optional texture disable)
+Below is slightly customized GPU Detection function taken from Perfect Assassin
+(the index7 latching works ONLY on New GPUs, whilst old GPUs would leave the
+latched value unchanged; as a workaround, the index4 latching is used to ensure
+that the latch won't contain 000002h on old GPUs, assuming that index4 is never
+set to 000002h).
+ [1F801814h]=10000004h ;GP1(10h).index4 (latch draw area bottom right)
+ [1F801814h]=10000007h ;GP1(10h).index7 (latch GPU version, if any)
+ if ([1F801810h] AND 00FFFFFFh)=00000002h then goto @@gpu_v2
+ [1F801810h]=([1F801814h] AND 3FFFh) OR E1001000h ;change GPUSTAT via GP0(E1h)
+ dummy=[1F801810h] ;dummy read (unknown purpose)
+ if ([1F801814h] AND 00001000h) then goto @@gpu_v1 else goto @@gpu_v0
+ ;---
+ @@gpu_v0: ;Old 160pin GPU (EARLY-PU-8)
+ return 0
+ ;---
+ @@gpu_v1: ;unknown GPU type, maybe some custom arcade/prototype version ?
+ if want_tex_dis then [1F801814h]=20000504h ;GP1(20h)
+ return 1
+ ;---
+ @@gpu_v2: ;New 208pin GPU (LATE-PU-8 and up)
+ if want_tex_dis then [1F801814h]=09000001h ;GP1(09h)
+ return 2
+
+GP0(02h) FillVram
+The FillVram command does normally ignore the lower 4bit of the x-coordinate
+(and software should always set those bits to zero). However, if the 4bits are
+all set, then the Old GPU does write each 2nd pixel to wrong memory address.
+For example, a 32x4 pixel fill produces following results for x=0..1Fh:
+ 0h 10h 20h 30h 40h
+ | | | | |
+ ################################ ;\x=00h..0Eh
+ ################################ ; and, x=0Fh
+ ################################ ; on NEW GPU
+ ################################ ;/
+ # # # # # # # ################## # # # # # # # ;\
+ # # # # # # # ################## # # # # # # # ; x=0Fh
+ # # # # # # # ################## # # # # # # # ; on OLD GPU
+ # # # # # # # ################## # # # # # # # ;/
+ ################################ ;\x=10h..1Eh
+ ################################ ; and, x=1Fh
+ ################################ ; on NEW GPU
+ ################################ ;/
+ # # # # # # # ################## # # # # # # # ;\
+ # # # # # # # ################## # # # # # # # ; x=1Fh
+ # # # # # # # ################## # # # # # # # ; on OLD GPU
+ # # # # # # # ################## # # # # # # # ;/
+
+Arcade GPUs
+Some arcade boards are using normal retail GPUs, however, there are also two
+special non-retail 208pin GPUs which seem to be solely used on arcade boards:
+ IC21 - 208pin - "SONY CXD8538Q" ;seen on GP-11 (namco System 11) boards
+ IC103 - 208pin - "SONY CXD8654Q" ;seen on GP-15 (namco System 12) boards
+The exact differences to retail GPUs are unknown. One of the special GPUs is
+said to use entierly different command numbers for rendering commands (maybe
+some old prototype variant, or maybe some protection against cloning arcade
+boards with retail chips).
+
+GPU Depth Ordering
+------------------
+
+Absent Depth Buffer
+The PlayStation's GPU stores only RGB colors in the framebuffer (ie. unlike
+modern 3D processors, it's NOT buffering Depth values; leaving apart the Mask
+bit, which could be considered as a tiny 1bit "Depth" or "Priority" value). In
+fact, the GPU supports only X,Y coordinates, and it's totally unaware of Z
+coordinates. So, when rendering a polygon, the hardware CANNOT determine which
+of the new pixels are in front/behind of the old pixels in the buffer.
+
+Simple Ordering
+The rendering simply takes place in the ordering as the data is sent to the GPU
+(ie. the most distant objects should be sent first). For 2D graphics, it's
+fairly easy follow that order (eg. even multi-layer 2D graphics can be using
+DMA2-continous mode).
+
+Depth Ordering Table (OT)
+For 3D graphics, the ordering of the polygons may change more or less randomly
+(eg. when rotating/moving the camera). To solve that problem, the whole
+rendering data is usually first stored in a Depth Ordering Table (OT) in Main
+RAM, and, once when all polygons have been stored in the OT, the OT is sent to
+the GPU via "DMA2-linked-list" mode.
+
+Initializing an empty OT (via DMA6)
+DMA channel 6 can be used to set up an empty linked list, in which each entry
+points to the previous:
+ DPCR - enable bits ;Example=x8xxxxxxh
+ D6_MADR - pointer to the LAST table entry ;Example=8012300Ch
+ D6_BCR - number of list entries ;Example=00000004h
+ D6_CHCR - control bits (should be 11000002h) ;Example=11000002h
+Each entry has a size of 00h words (upper 8bit), and a pointer to the previous
+entry (lower 24bit). With the above Example values, the generated table would
+look like so:
+ [80123000h]=00FFFFFFh ;1st entry, points to end code (xxFFFFFFh)
+ [80123004h]=00123000h ;2nd entry, points to 1st entry
+ [80123008h]=00123004h ;3rd entry, points to 2nd entry
+ [8012300Ch]=00123008h ;last entry, points to 3rd entry (table entrypoint)
+
+Inserting Entries (Passing GTE data to the OT) (by software)
+The GTE commands AVSZ3 and AVSZ4 can be used to calculate the Average Z
+coordinates of a polygon (based on its three or four Z coordinates). The result
+is returned as a 16bit Z value in GTE register OTZ, the commands do also allow
+to divide the result, to make it less than 16bit (the full 16bit would require
+an OT of 256KBytes - for the EMPTY table, which would be a waste of memory, and
+which would slowdown the DMA2/DMA6 operations) (on the other hand, a smaller
+table means less depth resolution).
+ [PacketAddr+0] = [80123000h+OTZ*4] + (N SHL 24) <--internal link chain
+ [PacketAddr+4..N*4] = GP0 Command(s) and Parameters <--data (send to GP0)
+ [80123000h+OTZ*4] = PacketAddr AND FFFFFFh <--internal link chain
+If there's been already an entry (at the same OTZ index), then the new polygon
+will be processed first (ie. it will appear "behind" of the old entry).
+Not sure if the packet size must be limited to max N=16 words (ie. as for the
+DMA2-continous block size) (due to GP0 FIFO size limits)?
+
+Sending the OT to the CPU (via DMA2-linked-list mode)
+ 1 - Wait until GPU is ready to receive commands ;GPUSTAT.28
+ 2 - Enable DMA channel 2 ;DPCR
+ 3 - Set GPU to DMA cpu->gpu mode ;[GP1]=04000002h aka GP1(04h)
+ 3 - Set D2_MADR to the start of the list ;(LAST Entry) ;Example=80123010h
+ 4 - Set D2_BCR to zero ;(length unused, end at END-CODE)
+ 5 - Set D2_CHCR to link mode, mem->GPU and dma enable ;=01000401h
+
+GPU Video Memory (VRAM)
+-----------------------
+
+Framebuffer
+The framebuffer contains the image that is to be output to the Television Set.
+The GPU supports 10 resolutions, with 16bit or 24bit per pixel.
+ Resolution 16bit 24bit | Resolution 16bit 24bit
+ 256x240 120Kbytes 180Kbytes | 256x480 240Kbytes 360Kbytes
+ 320x240 150Kbytes 225Kbytes | 320x480 300Kbytes 450Kbytes
+ 368x240 xx0Kbytes xx0Kbytes | 368x480 xx0Kbytes xx0Kbytes
+ 512x240 240Kbytes 360Kbytes | 512x480 480Kbytes 720Kbytes
+ 640x240 300Kbytes 450Kbytes | 640x480 600Kbytes 900Kbytes
+Note: In most cases, you'll need TWO framebuffers (one being displayed, and
+used as rendering target) (unless you are able to draw the whole new image
+during vblank, or unless when using single-layer 2D graphics). So, resolutions
+that occupy more than 512K would exceed the available 1MB VRAM when using 2
+buffers. Also, high resolutions mean higher rendering load, and less texture
+memory.
+ 15bit Direct Display (default) (works with polygons, lines, rectangles)
+ 0-4 Red (0..31)
+ 5-9 Green (0..31)
+ 10-14 Blue (0..31)
+ 15 Mask flag (0=Normal, 1=Do not allow to overwrite this pixel)
+ 24bit Direct Display (works ONLY with direct vram transfers)
+ 0-7 Red (0..255)
+ 8-15 Green (0..255)
+ 16-23 Blue (0..255)
+Note: The 24bit pixels occupy 3 bytes (not 4 bytes with unused MSBs), so each 6
+bytes contain two 24bit pixels. The 24bit display mode works only with VRAM
+transfer commands like GP0(A0h); the rendering commands GP0(20h..7Fh) cannot
+output 24bit data. Ie. 24bit mode is used mostly for MDEC videos (and some 2D
+games like Heart of Darkness).
+
+Texture Bitmaps
+A texture is an image put on a polygon or sprite. The data of a texture can be
+stored in 3 different modes:
+ 16bit Texture (Direct Color) ;(One 256x256 page = 128Kbytes)
+ 0-4 Red (0..31) ;\Color 0000h = Fully-Transparent
+ 5-9 Green (0..31) ; Color 0001h..7FFFh = Non-Transparent
+ 10-14 Blue (0..31) ; Color 8000h..FFFFh = Semi-Transparent (*)
+ 15 Semi Transparency Flag ;/(*) or Non-Transparent for opaque commands
+ 8bit Texture (256 Color Palette) ;(One 256x256 page = 64Kbytes)
+ 0-7 Palette index for 1st pixel (left)
+ 8-15 Palette index for 2nd pixel (right)
+ 4bit Texture (16 Color Palette) ;(One 256x256 page = 32Kbytes)
+ 0-3 Palette index for 1st pixel (left)
+ 4-7 Palette index for 2nd pixel (middle/left)
+ 8-11 Palette index for 3rd pixel (middle/right)
+ 12-15 Palette index for 4th pixel (right)
+A Texture Page is a 256x256 texel region in VRAM (the Polygon rendering
+commands are using Texcoords with 8bit X,Y coordinates, so polygons cannot use
+textures bigger than 256x256) (the Rectangle rendering commands with
+width/height parameters could theoretically use larger textures, but the
+hardware clips their texture coordinates to 8bit, too).
+The GP0(E2h) Texture Window (aka Texture Repeat) command can be used to reduce
+the texture size to less than 256x256 texels.
+The Texture Pages can be located in the frame buffer on X multiples of 64
+halfwords and Y multiples of 256 lines.
+
+Texture Palettes - CLUT (Color Lookup Table)
+The clut is a the table where the colors are stored for the image data in the
+CLUT modes. The pixels of those images are used as indexes to this table. The
+clut is arranged in the frame buffer as a 256x1 image for the 8bit clut mode,
+and a 16x1 image for the 4bit clut mode.
+ 0-4 Red (0..31) ;\Color 0000h = Fully-Transparent
+ 5-9 Green (0..31) ; Color 0001h..7FFFh = Non-Transparent
+ 10-14 Blue (0..31) ; Color 8000h..FFFFh = Semi-Transparent (*)
+ 15 Semi Transparency Flag ;/(*) or Non-Transparent for opaque commands
+The clut data can be arranged in the frame buffer at X multiples of 16
+(X=0,16,32,48,etc) and anywhere in the Y range of 0-511.
+
+Texture Color Black Limitations
+On the PSX, texture color 0000h is fully-transparent, that means textures
+cannot contain Black pixels. However, in some cases, Color 8000h (Black with
+semi-transparent flag) can be used, depending on the rendering command:
+ opaque command, eg. GP0(24h) --> 8000h = Non-Transparent Black
+ semi-transp command, eg. GP0(26h) --> 8000h = Semi-Transparent Black
+So, with semi-transparent rendering commands, it isn't possible to use
+Non-Transparent Black pixels in textures, the only workaround is to use colors
+like 0001h (dark red) or 0400h (dark blue). However, due to the PSX's rather
+steeply increasing intensity ramp, these colors are clearly visible to be
+brighter than black.
+
+RGB Intensity Notes
+The Playstations RGB values aren't linear to normal RGB values (as used on
+PCs). The min/max values are of course the same, but the medium values differ:
+ Intensity PC PSX
+ Minimum 0 0
+ Medium (circa) 16 8
+ Maximum 31 31
+Ie. on the PSX, the intensity increases steeply from 0 to 15, and less steeply
+from 16 to 31.
+
+GPU Texture Caching
+-------------------
+
+The GPU has 2 Kbyte Texture Cache
+The Texture Cache is (maybe) also used for CLUT data - or is there a separate
+CLUT Cache - or is the CLUT uncached - but that'd be trash?
+
+If polygons with texture are displayed, the GPU needs to read these from the
+frame buffer. This slows down the drawing process, and as a result the number
+of polygons that can be drawn in a given timespan. To speed up this process the
+GPU is equipped with a texture cache, so a given piece of texture needs not to
+be read multiple times in succession.
+The texture cache size depends on the color mode used for the textures.
+In 4 bit CLUT mode it has a size of 64x64, in 8 bit CLUT it's 32x64 and in
+15bitDirect is 32x32. A general speed up can be achieved by setting up textures
+according to these sizes. For further speed gain a more precise knowledge of
+how the cache works is necessary.
+
+Cache blocks
+The texture page is divided into non-overlapping cache blocks, each of a unit
+size according to color mode. These cache blocks are tiled within the texture
+page.
+ +-----+-----+-----+--
+ |cache| | |
+ |block| |
+ | 0| 1 | 2 ..
+ +-----+-----+--
+ |.. | |
+
+Cache entries
+Each cache block is divided into 256 cache entries, which are numbered
+sequentially, and are 8 bytes wide. So a cache entry holds 16 4bit clut pixels
+8 8bit clut pixels, or 4 15bitdirect pixels.
+ 4bit and 8bit clut: 15bitdirect:
+ +----+----+----+----+ +----+----+----+----+----+----+----+----+
+ | 0| 1| 2| 3| | 0| 1| 2| 3| 4| 5| 6| 7|
+ +----+----+----+----+ +----+----+----+----+----+----+----+----+
+ | 4| 5| 6| 7| | 8| 9| a| b| c| d| e| f|
+ +----+----+----+----+ +----+----+----+----+----+----+----+----+
+ | 8| 9| .. | 10| 11| ..
+ +----+----+-- +----+----+--
+ | c| ..| | 18| ..|
+ +----+-- +----+--
+ | .. | ..
+The cache can hold only one cache entry by the same number, so if f.e. a piece
+of texture spans multiple cache blocks and it has data on entry 9 of block 1,
+but also on entry 9 of block 2, these cannot be in the cache at once.
+
+GPU Timings
+-----------
+
+Video Clock
+The PSone/PAL video clock is the cpu clock multiplied by 11/7.
+ CPU Clock = 33.868800MHz (44100Hz*300h)
+ Video Clock = 53.222400MHz (44100Hz*300h*11/7)
+For other PSX/PSone PAL/NTSC variants, see:
+--> Pinouts - CLK Pinouts
+
+Vertical Timings
+ PAL: 314 scanlines per frame (13Ah)
+ NTSC: 263 scanlines per frame (107h)
+Timer1 can use the hblank signal as input, allowing to count scanlines (unless
+the display is configured to 0 pixels width, which would cause an endless
+hblank). The hblank signal is generated even during vertical blanking/retrace.
+
+Horizontal Timings
+ PAL: 3406 video cycles per scanline (or 3406.1 or so?)
+ NTSC: 3413 video cycles per scanline (or 3413.6 or so?)
+Dotclocks:
+ PSX.256-pix Dotclock = 5.322240MHz (44100Hz*300h*11/7/10)
+ PSX.320-pix Dotclock = 6.652800MHz (44100Hz*300h*11/7/8)
+ PSX.368-pix Dotclock = 7.603200MHz (44100Hz*300h*11/7/7)
+ PSX.512-pix Dotclock = 10.644480MHz (44100Hz*300h*11/7/5)
+ PSX.640-pix Dotclock = 13.305600MHz (44100Hz*300h*11/7/4)
+ Namco GunCon 385-pix = 8.000000MHz (from 8.00MHz on lightgun PCB)
+Dots per scanline are, depending on horizontal resolution, and on PAL/NTSC:
+ 320pix/PAL: 3406/8 = 425.75 dots 320pix/NTSC: 3413/8 = 426.625 dots
+ 640pix/PAL: 3406/4 = 851.5 dots 640pix/NTSC: 3413/4 = 853.25 dots
+ 256pix/PAL: 3406/10 = 340.6 dots 256pix/NTSC: 3413/10 = 341.3 dots
+ 512pix/PAL: 3406/5 = 681.2 dots 512pix/NTSC: 3413/5 = 682.6 dots
+ 368pix/PAL: 3406/7 = 486.5714 dots 368pix/NTSC: 3413/7 = 487.5714 dots
+Timer0 can use the dotclock as input, however, the Timer0 input "ignores" the
+fractional portions (in most cases, the values are rounded down, ie. with 340.6
+dots/line, the timer increments only 340 times/line; the only value that is
+rounded up is 425.75 dots/line) (for example, due to the rounding, the timer
+isn't running exactly twice as fast in 512pix/PAL mode than in 256pix/PAL
+mode). The dotclock signal is generated even during horizontal/vertical
+blanking/retrace.
+
+Frame Rates
+ PAL: 53.222400MHz/314/3406 = ca. 49.76 Hz (ie. almost 50Hz)
+ NTSC: 53.222400MHz/263/3413 = ca. 59.29 Hz (ie. almost 60Hz)
+
+Note
+Above values include "hidden" dots and scanlines (during horizontal and
+vertical blanking/retrace).
+
+GPU (MISC)
+----------
+
+GP0(20h..7Fh) - Render Command Bits
+ 0-23 Color for (first) Vertex (Not for Raw-Texture)
+ 24 Texture Mode (0=Blended, 1=Raw) (Textured-Polygon/Rect only)
+ 25 Semi Transparency (0=Off, 1=On) (All Render Types)
+ 26 Texture Mapping (0=Off, 1=On) (Polygon/Rectangle only)
+ 27-28 Rect Size (0=Var, 1=1x1, 2=8x8, 3=16x16) (Rectangle only)
+ 27 Num Vertices (0=Triple, 1=Quad) (Polygon only)
+ 27 Num Lines (0=Single, 1=Poly) (Line only)
+ 28 Shading (0=Flat, 1=Gouroud) (Polygon/Line only)
+ 29-31 Primitive Type (1=Polygon, 2=Line, 3=Rectangle)
+
+Perspective (in-)correct Rendering
+The PSX doesn't support perspective correct rendering: Assume a polygon to be
+rotated so that it's right half becomes more distant to the camera, and it's
+left half becomes closer. Due to the GTE's perspective division, the right half
+should appear smaller than the left half.
+The GPU supports only linear interpolations for rendering - that is correct
+concerning the X and Y screen coordinates (which are still linear to each
+other, even after perspective division, since both are divided by the same
+value).
+However, texture coordinates (and Gouraud shaded colors) are NOT linear to the
+screen coordinates, and so, the linear interpolated PSX graphics are often
+looking rather distorted, that especially for textures that contain straight
+lines. For color shading the problem is less obvious (since shading is kinda
+blurry anyways).
+
+Perspective correct Rendering
+For perspective correct rendering, the polygon's Z-coordinates would be needed
+to be passed from the GTE to the GPU, and, the GPU would then need to use that
+Z-coordinates to "undo" the perspective division for each pixel (that'd require
+some additional memory, and especially a powerful division unit, which isn't
+implemented in the hardware).
+As a workaround, you can try to reduce the size of your polygons (the
+interpolation errors increase in the center region of larger polygons).
+Reducing the size would be only required for polygons that occupy a larger
+screen region (which may vary depending on the distance to the camera).
+Ie. you may check the size AFTER perspective division, if it's too large, then
+break it into smaller parts (using the original coordinates, NOT the screen
+coordinates), and then pass the fragments to the GTE another time.
+Again, perspective correction would be relevant only for certain textures (not
+for randomly dithered textures like sand, water, fire, grass, and not for
+untextured polygons, and of course not for 2D graphics, so you may exclude
+those from size reduction).
+
+24bit RGB to 15bit RGB Dithering (enabled in Texpage attribute)
+For dithering, VRAM is broken to 4x4 pixel blocks, depending on the location in
+that 4x4 pixel region, the corresponding dither offset is added to the 8bit
+R/G/B values, the result is saturated to +00h..+FFh, and then divided by 8,
+resulting in the final 5bit R/G/B values.
+ -4 +0 -3 +1 ;\dither offsets for first two scanlines
+ +2 -2 +3 -1 ;/
+ -3 +1 -4 +0 ;\dither offsets for next two scanlines
+ +3 -1 +2 -2 ;/(same as above, but shifted two pixels horizontally)
+POLYGONs (triangles/quads) are dithered ONLY if they do use gouraud shading or
+texture blending.
+LINEs are dithered (no matter if they are mono or do use gouraud shading).
+RECTs are NOT dithered (no matter if they do use texture blending).
+
+Shading information
+"Texture RGB values control the brightness of the individual colors ($00-$7f).
+A value of $80 in a color will take the former value as data." (What...?
+probably means the "double brightness" effect... or does it want to tell that
+ALL colors of 80h..FFh have only single brightness.. rather than reaching
+double brightness at FFh...?)
+
+Shading
+The GPU has a shading function, which will scale the color of a primitive to a
+specified brightness. There are 2 shading modes: Flat shading, and gouraud
+shading. Flat shading is the mode in which one brightness value is specified
+for the entire primitive. In Gouraud shading mode, a different brightness value
+can be given for each vertex of a primitive, and the brightness between these
+points is automatically interpolated.
+
+Semi Transparency
+When semi transparency is set for a pixel, the GPU first reads the pixel it
+wants to write to, and then calculates the color it will write from the 2
+pixels according to the semitransparency mode selected. Processing speed is
+lower in this mode because additional reading and calculating are necessary.
+There are 4 semitransparency modes in the GPU.
+ B=Back (the old pixel read from the image in the frame buffer)
+ F=Front (the new halftransparent pixel)
+ * 0.5 x B + 0.5 x F ;aka B/2+F/2
+ * 1.0 x B + 1.0 x F ;aka B+F
+ * 1.0 x B - 1.0 x F ;aka B-F
+ * 1.0 x B +0.25 x F ;aka B+F/4
+
+Draw to display enable
+This will enable/disable any drawing to the area that is currently displayed.
+Not sure yet WHY one should want to disable that?
+Also not sure HOW and IF it works... the SIZE of the display area is implied by
+the screen size - which is horizontally counted in CLOCK CYCLES, so, to obtain
+the size in PIXELS, the hardware would require to divide that value by the
+number of cycles per pixel, depending on the current resolution...?
+
+Geometry Transformation Engine (GTE)
+------------------------------------
+
+--> GTE Overview
+--> GTE Registers
+--> GTE Saturation
+--> GTE Opcode Summary
+--> GTE Coordinate Calculation Commands
+--> GTE General Purpose Calculation Commands
+--> GTE Color Calculation Commands
+--> GTE Division Inaccuracy
+
+GTE Overview
+------------
+
+GTE Operation
+The GTE doesn't have any memory or I/O ports mapped to the CPU memory bus,
+instead, it's solely accessed via coprocessor opcodes:
+ mov cop0r12,rt ;-enable/disable COP2 (GTE) via COP0 status register
+ mov cop2r0-63,rt ;\write parameters to GTE registers
+ mov cop2r0-31,[rs+imm] ;/
+ mov cop2cmd,imm25 ;-issue GTE command
+ mov rt,cop2r0-63 ;\read results from GTE registers
+ mov [rs+imm],cop2r0-31 ;/
+ jt cop2flg,dest ;-jump never ;\implemented (no exception), but,
+ jf cop2flg,dest ;-jump always ;/flag seems to be always "false"
+GTE (memory-?) load and store instructions have a delay of 2 instructions, for
+any GTE commands or operations accessing that register. Any? That's wrong!
+GTE instructions and functions should not be used in
+ - Delay slots of jumps and branches
+ - Event handlers or interrupts (sounds like nonsense?) (need push/pop though)
+If an instruction that reads a GTE register or a GTE command is executed before
+the current GTE command is finished, the CPU will hold until the instruction
+has finished. The number of cycles each GTE instruction takes is shown in the
+command list.
+
+GTE Command Encoding (COP2 imm25 opcodes)
+ 31-25 Must be 0100101b for "COP2 imm25" instructions
+ 20-24 Fake GTE Command Number (00h..1Fh) (ignored by hardware)
+ 19 sf - Shift Fraction in IR registers (0=No fraction, 1=12bit fraction)
+ 17-18 MVMVA Multiply Matrix (0=Rotation. 1=Light, 2=Color, 3=Reserved)
+ 15-16 MVMVA Multiply Vector (0=V0, 1=V1, 2=V2, 3=IR/long)
+ 13-14 MVMVA Translation Vector (0=TR, 1=BK, 2=FC/Bugged, 3=None)
+ 11-12 Always zero (ignored by hardware)
+ 10 lm - Saturate IR1,IR2,IR3 result (0=To -8000h..+7FFFh, 1=To 0..+7FFFh)
+ 6-9 Always zero (ignored by hardware)
+ 0-5 Real GTE Command Number (00h..3Fh) (used by hardware)
+The MVMVA bits are used only by the MVMVA opcode (the bits are zero for all
+other opcodes).
+The "sf" and "lm" bits are usually fixed (either set, or cleared, depending on
+the command) (for MVMVA, the bits are variable) (also, "sf" can be changed for
+some commands like SQR) (although they are usually fixed for most other
+opcodes, changing them might have some effect on some/all opcodes)?
+
+GTE Data Register Summary (cop2r0-31)
+ cop2r0-1 3xS16 VXY0,VZ0 Vector 0 (X,Y,Z)
+ cop2r2-3 3xS16 VXY1,VZ1 Vector 1 (X,Y,Z)
+ cop2r4-5 3xS16 VXY2,VZ2 Vector 2 (X,Y,Z)
+ cop2r6 4xU8 RGBC Color/code value
+ cop2r7 1xU16 OTZ Average Z value (for Ordering Table)
+ cop2r8 1xS16 IR0 16bit Accumulator (Interpolate)
+ cop2r9-11 3xS16 IR1,IR2,IR3 16bit Accumulator (Vector)
+ cop2r12-15 6xS16 SXY0,SXY1,SXY2,SXYP Screen XY-coordinate FIFO (3 stages)
+ cop2r16-19 4xU16 SZ0,SZ1,SZ2,SZ3 Screen Z-coordinate FIFO (4 stages)
+ cop2r20-22 12xU8 RGB0,RGB1,RGB2 Color CRGB-code/color FIFO (3 stages)
+ cop2r23 4xU8 (RES1) Prohibited
+ cop2r24 1xS32 MAC0 32bit Maths Accumulators (Value)
+ cop2r25-27 3xS32 MAC1,MAC2,MAC3 32bit Maths Accumulators (Vector)
+ cop2r28-29 1xU15 IRGB,ORGB Convert RGB Color (48bit vs 15bit)
+ cop2r30-31 2xS32 LZCS,LZCR Count Leading-Zeroes/Ones (sign bits)
+
+GTE Control Register Summary (cop2r32-63)
+ cop2r32-36 9xS16 RT11RT12,..,RT33 Rotation matrix (3x3) ;cnt0-4
+ cop2r37-39 3x 32 TRX,TRY,TRZ Translation vector (X,Y,Z) ;cnt5-7
+ cop2r40-44 9xS16 L11L12,..,L33 Light source matrix (3x3) ;cnt8-12
+ cop2r45-47 3x 32 RBK,GBK,BBK Background color (R,G,B) ;cnt13-15
+ cop2r48-52 9xS16 LR1LR2,..,LB3 Light color matrix source (3x3) ;cnt16-20
+ cop2r53-55 3x 32 RFC,GFC,BFC Far color (R,G,B) ;cnt21-23
+ cop2r56-57 2x 32 OFX,OFY Screen offset (X,Y) ;cnt24-25
+ cop2r58 BuggyU16 H Projection plane distance. ;cnt26
+ cop2r59 S16 DQA Depth queing parameter A (coeff) ;cnt27
+ cop2r60 32 DQB Depth queing parameter B (offset);cnt28
+ cop2r61-62 2xS16 ZSF3,ZSF4 Average Z scale factors ;cnt29-30
+ cop2r63 U20 FLAG Returns any calculation errors ;cnt31
+
+GTE Registers
+-------------
+
+Note in some functions format is different from the one that's given here.
+
+Matrix Registers
+ Rotation matrix (RT) Light matrix (LLM) Light Color matrix (LCM)
+ cop2r32.lsbs=RT11 cop2r40.lsbs=L11 cop2r48.lsbs=LR1
+ cop2r32.msbs=RT12 cop2r40.msbs=L12 cop2r48.msbs=LR2
+ cop2r33.lsbs=RT13 cop2r41.lsbs=L13 cop2r49.lsbs=LR3
+ cop2r33.msbs=RT21 cop2r41.msbs=L21 cop2r49.msbs=LG1
+ cop2r34.lsbs=RT22 cop2r42.lsbs=L22 cop2r50.lsbs=LG2
+ cop2r34.msbs=RT23 cop2r42.msbs=L23 cop2r50.msbs=LG3
+ cop2r35.lsbs=RT31 cop2r43.lsbs=L31 cop2r51.lsbs=LB1
+ cop2r35.msbs=RT32 cop2r43.msbs=L32 cop2r51.msbs=LB2
+ cop2r36 =RT33 cop2r44 =L33 cop2r52 =LB3
+Each element is 16bit (1bit sign, 3bit integer, 12bit fraction). Reading the
+last elements (RT33,L33,LB3) returns the 16bit value sign-expanded to 32bit.
+
+Translation Vector (TR) (Input, R/W?)
+ cop2r37 (cnt5) - TRX - Translation vector X (R/W?)
+ cop2r38 (cnt6) - TRY - Translation vector Y (R/W?)
+ cop2r39 (cnt7) - TRZ - Translation vector Z (R/W?)
+Each element is 32bit (1bit sign, 31bit integer).
+Used only for MVMVA, RTPS, RTPT commands.
+
+Background Color (BK) (Input?, R/W?)
+ cop2r45 (cnt13) - RBK - Background color red component
+ cop2r46 (cnt14) - GBK - Background color green component
+ cop2r47 (cnt15) - BBK - Background color blue component
+Each element is 32bit (1bit sign, 19bit integer, 12bit fraction).
+
+Far Color (FC) (Input?) (R/W?)
+ cop2r53 (cnt21) - RFC - Far color red component
+ cop2r54 (cnt22) - GFC - Far color green component
+ cop2r55 (cnt23) - BFC - Far color blue component
+Each element is 32bit (1bit sign, 27bit integer, 4bit fraction).
+
+Screen Offset and Distance (Input, R/W?)
+ cop2r56 (cnt24) - OFX - Screen offset X
+ cop2r57 (cnt25) - OFY - Screen offset Y
+ cop2r58 (cnt26) - H - Projection plane distance
+ cop2r59 (cnt27) - DQA - Depth queing parameter A.(coeff.)
+ cop2r60 (cnt28) - DQB - Depth queing parameter B.(offset.)
+The X and Y values are each 32bit (1bit sign, 15bit integer, 16bit fraction).
+The H value is 16bit unsigned (0bit sign, 16bit integer, 0bit fraction). BUG:
+When reading the H register, the hardware does accidently <sign-expand> the
+<unsigned> 16bit value (ie. values +8000h..+FFFFh are returned as
+FFFF8000h..FFFFFFFFh) (this bug applies only to "mov rd,cop2r58" opcodes; the
+actual calculations via RTPS/RTPT opcodes are working okay).
+The DQA value is only 16bit (1bit sign, 7bit integer, 8bit fraction).
+The DQB value is 32bit (1bit sign, 7bit integer, 24bit? fraction).
+Used only for RTPS/RTPT commands.
+
+Average Z Registers (ZSF3/ZSF4=Input, R/W?) (OTZ=Result, R)
+ cop2r61 (cnt29) ZSF3 | 0|ZSF3 1,3,12| Z3 average scale factor (normally 1/3)
+ cop2r62 (cnt30) ZSF4 | 0|ZSF4 1,3,12| Z4 average scale factor (normally 1/4)
+ cop2r7 OTZ (R) | |OTZ 0,15, 0| Average Z value (for Ordering Table)
+Used only for AVSZ3/AVSZ4 commands.
+
+Screen XYZ Coordinate FIFOs
+ cop2r12 - SXY0 rw|SY0 1,15, 0|SX0 1,15, 0| Screen XY fifo (older)
+ cop2r13 - SXY1 rw|SY1 1,15, 0|SX1 1,15, 0| Screen XY fifo (old)
+ cop2r14 - SXY2 rw|SY2 1,15, 0|SX2 1,15, 0| Screen XY fifo (new)
+ cop2r15 - SXYP rw|SYP 1,15, 0|SXP 1,15, 0| SXY2-mirror with move-on-write
+ cop2r16 - SZ0 rw| 0|SZ0 0,16, 0| Screen Z fifo (oldest)
+ cop2r17 - SZ1 rw| 0|SZ1 0,16, 0| Screen Z fifo (older)
+ cop2r18 - SZ2 rw| 0|SZ2 0,16, 0| Screen Z fifo (old)
+ cop2r19 - SZ3 rw| 0|SZ3 0,16, 0| Screen Z fifo (new)
+SX,SY,SZ are used as Output for RTPS/RTPT. Additionally, SX,SY are used as
+Input for NCLIP, and SZ is used as Input for AVSZ3/AVSZ4.
+The SZn Fifo has 4 stages (required for AVSZ4 command), the SXYn Fifo has only
+3 stages, and a special mirrored register: SXYP is a mirror of SXY2, the
+difference is that writing to SXYP moves SXY2/SXY1 to SXY1/SXY0, whilst writing
+to SXY2 (or any other SXYn or SZn registers) changes only the written register,
+but doesn't move any other Fifo entries.
+
+16bit Vectors (R/W)
+ Vector 0 (V0) Vector 1 (V1) Vector 2 (V2) Vector 3 (IR)
+ cop2r0.lsbs - VX0 cop2r2.lsbs - VX1 cop2r4.lsbs - VX2 cop2r9 - IR1
+ cop2r0.msbs - VY0 cop2r2.msbs - VY1 cop2r4.msbs - VY2 cop2r10 - IR2
+ cop2r1 - VZ0 cop2r3 - VZ1 cop2r5 - VZ2 cop2r11 - IR3
+All elements are signed 16bit. The IRn and VZn elements occupy a whole 32bit
+register, reading these registers returns the 16bit value sign-expanded to
+32bit. Note: IRn can be also indirectly accessed via IRGB/ORGB registers.
+
+Color Register and Color FIFO
+ cop2r6 - RGBC rw|CODE |B |G |R | Color/code
+ cop2r20 - RGB0 rw|CD0 |B0 |G0 |R0 | Characteristic color fifo.
+ cop2r21 - RGB1 rw|CD1 |B1 |G1 |R1 |
+ cop2r22 - RGB2 rw|CD2 |B2 |G2 |R2 |
+ cop2r23 - (RES1) | | Prohibited
+RES1 seems to be unused... looks like an unused Fifo stage... RES1 is
+read/write-able... unlike SXYP (for SXYn Fifo) it does not mirror to RGB2, nor
+does it have a move-on-write function...
+
+Interpolation Factor
+ cop2r8 IR0 rw|Sign |IR0 1, 3,12| Intermediate value 0.
+Used as Output for RTPS/RTPT, and as Input for various commands.
+
+XX...
+ cop2r24 MAC0 rw|MAC0 1,31,0 | Sum of products value 0
+
+XX...
+ cop2r25 MAC1 rw|MAC1 1,31,0 | Sum of products value 1
+ cop2r26 MAC2 rw|MAC2 1,31,0 | Sum of products value 2
+ cop2r27 MAC3 rw|MAC3 1,31,0 | Sum of products value 3
+
+cop2r28 - IRGB - Color conversion Input (R/W)
+Expands 5:5:5 bit RGB (range 0..1Fh) to 16:16:16 bit RGB (range 0000h..0F80h).
+ 0-4 Red (0..1Fh) (R/W) ;multiplied by 80h, and written to IR1
+ 5-9 Green (0..1Fh) (R/W) ;multiplied by 80h, and written to IR2
+ 10-14 Blue (0..1Fh) (R/W) ;multiplied by 80h, and written to IR3
+ 15-31 Not used (always zero) (Read only)
+After writing to IRGB, the result can be read from IR3 after TWO nop's, and
+from IR1,IR2 after THREE nop's (for uncached code, ONE nop would work). When
+using IR1,IR2,IR3 as parameters for GTE commands, similar timing restrictions
+might apply... depending on when the specific commands use the parameters?
+
+cop2r29 - ORGB - Color conversion Output (R)
+Collapses 16:16:16 bit RGB (range 0000h..0F80h) to 5:5:5 bit RGB (range
+0..1Fh). Negative values (8000h..FFFFh/80h) are saturated to 00h, large
+positive values (1000h..7FFFh/80h) are saturated to 1Fh, there are no overflow
+or saturation flags set in cop2r63 though.
+ 0-4 Red (0..1Fh) (R) ;IR1 divided by 80h, saturated to +00h..+1Fh
+ 5-9 Green (0..1Fh) (R) ;IR2 divided by 80h, saturated to +00h..+1Fh
+ 10-14 Blue (0..1Fh) (R) ;IR3 divided by 80h, saturated to +00h..+1Fh
+ 15-31 Not used (always zero) (Read only)
+Any changes to IR1,IR2,IR3 are reflected to this register (and, actually also
+to IRGB) (ie. ORGB is simply a read-only mirror of IRGB).
+
+cop2r30 - LZCS - Count Leading Bits Source data (R/W)
+cop2r31 - LZCR - Count Leading Bits Result (R)
+Reading LZCR returns the leading 0 count of LZCS if LZCS is positive and the
+leading 1 count of LZCS if LZCS is negative. The results are in range 1..32.
+
+cop2r63 (cnt31) - FLAG - Returns any calculation errors.
+See GTE Saturation chapter.
+
+GTE Saturation
+--------------
+
+Maths overflows are indicated in FLAG register. In most cases, the result is
+saturated to MIN/MAX values (except MAC0,MAC1,MAC2,MAC3 which aren't
+saturated). For IR1,IR2,IR3 many commands allow to select the MIN value via
+"lm" bit of the GTE opcode (though not all commands, RTPS/RTPT always act as if
+lm=0).
+
+cop2r63 (cnt31) - FLAG - Returns any calculation errors.
+ 31 Error Flag (Bit30..23, and 18..13 ORed together) (Read only)
+ 30 MAC1 Result larger than 43 bits and positive
+ 29 MAC2 Result larger than 43 bits and positive
+ 28 MAC3 Result larger than 43 bits and positive
+ 27 MAC1 Result larger than 43 bits and negative
+ 26 MAC2 Result larger than 43 bits and negative
+ 25 MAC3 Result larger than 43 bits and negative
+ 24 IR1 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
+ 23 IR2 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
+ 22 IR3 saturated to +0000h..+7FFFh (lm=1) or to -8000h..+7FFFh (lm=0)
+ 21 Color-FIFO-R saturated to +00h..+FFh
+ 20 Color-FIFO-G saturated to +00h..+FFh
+ 19 Color-FIFO-B saturated to +00h..+FFh
+ 18 SZ3 or OTZ saturated to +0000h..+FFFFh
+ 17 Divide overflow. RTPS/RTPT division result saturated to max=1FFFFh
+ 16 MAC0 Result larger than 31 bits and positive
+ 15 MAC0 Result larger than 31 bits and negative
+ 14 SX2 saturated to -0400h..+03FFh
+ 13 SY2 saturated to -0400h..+03FFh
+ 12 IR0 saturated to +0000h..+1000h
+ 0-11 Not used (always zero) (Read only)
+Bit30-12 are read/write-able, ie. they can be set/reset by software, however,
+that's normally not required - all bits are automatically reset at the begin of
+a new GTE command.
+Bit31 is apparently intended for RTPS/RTPT commands, since it triggers only on
+flags that are affected by these two commands, but even for that commands it's
+totally useless since one could as well check if FLAG is nonzero.
+Note: Writing 32bit values to 16bit GTE registers by software does not trigger
+any overflow/saturation flags (and does not do any saturation), eg. writing
+12008900h (positive 32bit) to a signed 16bit register sets that register to
+FFFF8900h (negative 16bit).
+
+GTE Opcode Summary
+------------------
+
+GTE Command Summary (sorted by Real Opcode bits) (bit0-5)
+ Opc Name Clk Expl.
+ 00h - N/A (modifies similar registers than RTPS...)
+ 01h RTPS 15 Perspective Transformation single
+ 0xh - N/A
+ 06h NCLIP 8 Normal clipping
+ 0xh - N/A
+ 0Ch OP(sf) 6 Outer product of 2 vectors
+ 0xh - N/A
+ 10h DPCS 8 Depth Cueing single
+ 11h INTPL 8 Interpolation of a vector and far color vector
+ 12h MVMVA(..) 8 Multiply vector by matrix and add vector (see below)
+ 13h NCDS 19 Normal color depth cue single vector
+ 14h CDP 13 Color Depth Que
+ 15h - N/A
+ 16h NCDT 44 Normal color depth cue triple vectors
+ 1xh - N/A
+ 1Bh NCCS 17 Normal Color Color single vector
+ 1Ch CC 11 Color Color
+ 1Dh - N/A
+ 1Eh NCS 14 Normal color single
+ 1Fh - N/A
+ 20h NCT 30 Normal color triple
+ 2xh - N/A
+ 28h SQR(sf) 5 Square of vector IR
+ 29h DCPL 8 Depth Cue Color light
+ 2Ah DPCT 17 Depth Cueing triple (should be fake=08h, but isn't)
+ 2xh - N/A
+ 2Dh AVSZ3 5 Average of three Z values
+ 2Eh AVSZ4 6 Average of four Z values
+ 2Fh - N/A
+ 30h RTPT 23 Perspective Transformation triple
+ 3xh - N/A
+ 3Dh GPF(sf) 5 General purpose interpolation
+ 3Eh GPL(sf) 5 General purpose interpolation with base
+ 3Fh NCCT 39 Normal Color Color triple vector
+Unknown if/what happens when using the "N/A" opcodes?
+
+GTE Command Summary (sorted by Fake Opcode bits) (bit20-24)
+The fake opcode number in bit20-24 has absolutely no effect on the hardware, it
+seems to be solely used to (or not to) confuse developers. Having the opcodes
+sorted by their fake numbers gives a more or less well arranged list:
+ Fake Name Clk Expl.
+ 00h - N/A
+ 01h RTPS 15 Perspective Transformation single
+ 02h RTPT 23 Perspective Transformation triple
+ 03h - N/A
+ 04h MVMVA(..) 8 Multiply vector by matrix and add vector (see below)
+ 05h - N/A
+ 06h DCPL 8 Depth Cue Color light
+ 07h DPCS 8 Depth Cueing single
+ 08h DPCT 17 Depth Cueing triple (should be fake=08h, but isn't)
+ 09h INTPL 8 Interpolation of a vector and far color vector
+ 0Ah SQR(sf) 5 Square of vector IR
+ 0Bh - N/A
+ 0Ch NCS 14 Normal color single
+ 0Dh NCT 30 Normal color triple
+ 0Eh NCDS 19 Normal color depth cue single vector
+ 0Fh NCDT 44 Normal color depth cue triple vectors
+ 10h NCCS 17 Normal Color Color single vector
+ 11h NCCT 39 Normal Color Color triple vector
+ 12h CDP 13 Color Depth Que
+ 13h CC 11 Color Color
+ 14h NCLIP 8 Normal clipping
+ 15h AVSZ3 5 Average of three Z values
+ 16h AVSZ4 6 Average of four Z values
+ 17h OP(sf) 6 Outer product of 2 vectors
+ 18h - N/A
+ 19h GPF(sf) 5 General purpose interpolation
+ 1Ah GPL(sf) 5 General purpose interpolation with base
+ 1Bh - N/A
+ 1Ch - N/A
+ 1Dh - N/A
+ 1Eh - N/A
+ 1Fh - N/A
+For the sort-effect, DCPT should use fake=08h, but Sony seems to have
+accidently numbered it fake=0Fh in their devkit (giving it the same fake number
+as for NCDT). Also, "Wipeout 2097" accidently uses 0140006h (fake=01h and
+distorted bit18) instead of 1400006h (fake=14h) for NCLIP.
+
+GTE nonsense SDK command numbers (as from SDK file INLINE_A.H)
+ RTPS macro dw $0000007f (01x40)
+ RTPT macro dw $000000bf (02x40)
+ DCPL macro dw $00000dff (37x40)
+ DPCS macro dw $00000e3f (38x40)
+ DPCT macro dw $00000e7f (39x40)
+ INTPL macro dw $00000ebf (3Ax40)
+ NCS macro dw $00000f7f (3Dx40)
+ NCT macro dw $00000fbf (3Ex40)
+ NCDS macro dw $00000fff (3Fx40)
+ NCDT macro dw $0000103f (40x40)
+ NCCS macro dw $0000107f (41x40)
+ NCCT macro dw $000010bf (42x40)
+ CDP macro dw $000010ff (43x40)
+ CC macro dw $0000113f (44x40)
+ NCLIP macro dw $0000117f (45x40)
+ AVSZ3 macro dw $000011bf (46x40)
+ AVSZ4 macro dw $000011ff (47x40)
+ MVMVA macro sf,mx,v,cv,lm dw $000013bf|sf<<25|mx<<23|v<<21|cv<<19|lm<<18
+ SQR macro sf dw $000013ff|sf<<25 (4Fx40)
+ OP macro sf dw $0000143f|sf<<25 (50x40)
+ GPF macro sf dw $0000147f|sf<<25 (51x40)
+ GPL macro sf dw $000014bf|sf<<25 (52x40)
+"Be warned that the DWORD codes are actually not GTE cop2 instructions. The way
+you deal with them in the official SDK is that you'd run the compiled object
+file of your assembly source that uses said macros through DMPSX which
+translates those DWORD codes into the correct GTE cop2 instructions. I don't
+know why Sony made it this way."
+
+Additional Functions
+The LZCS/LZCR registers offer a Count-Leading-Zeroes/Leading-Ones function.
+The IRGB/ORGB registers allow to convert between 48bit and 15bit RGB colors.
+These registers work without needing to send any COP2 commands. However, unlike
+for commands (which do automatically halt the CPU when needed), one must insert
+dummy opcodes between writing and reading the registers.
+
+GTE Coordinate Calculation Commands
+-----------------------------------
+
+COP2 0180001h - 15 Cycles - RTPS - Perspective Transformation (single)
+COP2 0280030h - 23 Cycles - RTPT - Perspective Transformation (triple)
+RTPS performs final Rotate, translate and perspective transformation on vertex
+V0. Before writing to the FIFOs, the older entries are moved one stage down.
+RTPT is same as RTPS, but repeats for V1 and V2. The "sf" bit should be usually
+set.
+ IR1 = MAC1 = (TRX*1000h + RT11*VX0 + RT12*VY0 + RT13*VZ0) SAR (sf*12)
+ IR2 = MAC2 = (TRY*1000h + RT21*VX0 + RT22*VY0 + RT23*VZ0) SAR (sf*12)
+ IR3 = MAC3 = (TRZ*1000h + RT31*VX0 + RT32*VY0 + RT33*VZ0) SAR (sf*12)
+ SZ3 = MAC3 SAR ((1-sf)*12) ;ScreenZ FIFO 0..+FFFFh
+ MAC0=(((H*20000h/SZ3)+1)/2)*IR1+OFX, SX2=MAC0/10000h ;ScrX FIFO -400h..+3FFh
+ MAC0=(((H*20000h/SZ3)+1)/2)*IR2+OFY, SY2=MAC0/10000h ;ScrY FIFO -400h..+3FFh
+ MAC0=(((H*20000h/SZ3)+1)/2)*DQA+DQB, IR0=MAC0/1000h ;Depth cueing 0..+1000h
+If the result of the "(((H*20000h/SZ3)+1)/2)" division is greater than 1FFFFh,
+then the division result is saturated to +1FFFFh, and the divide overflow bit
+in the FLAG register gets set; that happens if the vertex is exceeding the
+"near clip plane", ie. if it is very close to the camera (SZ3<=H/2), exactly at
+the camara position (SZ3=0), or behind the camera (negative Z coordinates are
+saturated to SZ3=0). For details on the division, see:
+--> GTE Division Inaccuracy
+For "far plane clipping", one can use the SZ3 saturation flag (MaxZ=FFFFh), or
+the IR3 saturation flag (MaxZ=7FFFh) (eg. used by Wipeout 2097), or one can
+compare the SZ3 value with any desired MaxZ value by software.
+Note: The command does saturate IR1,IR2,IR3 to -8000h..+7FFFh (regardless of lm
+bit). When using RTP with sf=0, then the IR3 saturation flag (FLAG.22) gets set
+<only> if "MAC3 SAR 12" exceeds -8000h..+7FFFh (although IR3 is saturated when
+"MAC3" exceeds -8000h..+7FFFh).
+
+COP2 1400006h - 8 Cycles - NCLIP - Normal clipping
+ MAC0 = SX0*SY1 + SX1*SY2 + SX2*SY0 - SX0*SY2 - SX1*SY0 - SX2*SY1
+The sign of the result indicates whether the polygon coordinates are arranged
+clockwise or anticlockwise (ie. whether the front side or backside is visible).
+If the result is zero, then it's neither one (ie. the vertices are all arranged
+in a straight line). Note: The GPU probably renders straight lines as invisble
+0 pixel width lines?
+
+COP2 158002Dh - 5 Cycles - AVSZ3 - Average of three Z values (for Triangles)
+COP2 168002Eh - 6 Cycles - AVSZ4 - Average of four Z values (for Quads)
+ MAC0 = ZSF3*(SZ1+SZ2+SZ3) ;for AVSZ3
+ MAC0 = ZSF4*(SZ0+SZ1+SZ2+SZ3) ;for AVSZ4
+ OTZ = MAC0/1000h ;for both (saturated to 0..FFFFh)
+Adds three or four Z values together and multplies them by a fixed point value.
+The result can be used as index in the GPU's Ordering Table (OT).
+--> GPU Depth Ordering
+The scaling factors would be usually ZSF3=N/30h and ZSF4=N/40h, where "N" is
+the number of entries in the OT (max 10000h). SZn and OTZ are unsigned 16bit
+values, for whatever reason ZSFn registers are signed 16bit values (negative
+values would allow a negative result in MAC0, but would saturate OTZ to zero).
+
+GTE General Purpose Calculation Commands
+----------------------------------------
+
+COP2 0400012h - 8 Cycles - MVMVA(sf,mx,v,cv,lm)
+Multiply vector by matrix and vector addition.
+ Mx = matrix specified by mx ;RT/LLM/LCM - Rotation, light or color matrix
+ Vx = vector specified by v ;V0, V1, V2, or [IR1,IR2,IR3]
+ Tx = translation vector specified by cv ;TR or BK or Bugged/FC, or None
+Calculation:
+ MAC1 = (Tx1*1000h + Mx11*Vx1 + Mx12*Vx2 + Mx13*Vx3) SAR (sf*12)
+ MAC2 = (Tx2*1000h + Mx21*Vx1 + Mx22*Vx2 + Mx23*Vx3) SAR (sf*12)
+ MAC3 = (Tx3*1000h + Mx31*Vx1 + Mx32*Vx2 + Mx33*Vx3) SAR (sf*12)
+ [IR1,IR2,IR3] = [MAC1,MAC2,MAC3]
+Multiplies a vector with either the rotation matrix, the light matrix or the
+color matrix and then adds the translation vector or background color vector.
+The GTE also allows selection of the far color vector (FC), but this vector is
+not added correctly by the hardware: The return values are reduced to the last
+portion of the formula, ie. MAC1=(Mx13*Vx3) SAR (sf*12), and similar for MAC2
+and MAC3, nethertheless, some bits in the FLAG register seem to be adjusted as
+if the full operation would have been executed. Setting Mx=3 selects a garbage
+matrix (with elements -60h, +60h, IR0, RT13, RT13, RT13, RT22, RT22, RT22).
+
+COP2 0A00428h+sf*80000h - 5 Cycles - SQR(sf) - Square vector
+ [MAC1,MAC2,MAC3] = [IR1*IR1,IR2*IR2,IR3*IR3] SHR (sf*12)
+ [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] ;IR1,IR2,IR3 saturated to max 7FFFh
+Calculates the square of a vector. The result is, of course, always positive,
+so the "lm" flag for negative saturation has no effect.
+
+COP2 170000Ch+sf*80000h - 6 Cycles - OP(sf,lm) - Outer product of 2 vectors
+ [MAC1,MAC2,MAC3] = [IR3*D2-IR2*D3, IR1*D3-IR3*D1, IR2*D1-IR1*D2] SAR (sf*12)
+ [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] ;copy result
+Calculates the outer product of two signed 16bit vectors. Note: D1,D2,D3 are
+meant to be the RT11,RT22,RT33 elements of the RT matrix "misused" as vector.
+lm should be usually zero.
+
+LZCS/LZCR registers - ? Cycles - Count-Leading-Zeroes/Leading-Ones
+The LZCS/LZCR registers offer a Count-Leading-Zeroes/Leading-Ones function.
+
+GTE Color Calculation Commands
+------------------------------
+
+COP2 0C8041Eh - 14 Cycles - NCS - Normal color (single)
+COP2 0D80420h - 30 Cycles - NCT - Normal color (triple)
+COP2 108041Bh - 17 Cycles - NCCS - Normal Color Color (single vector)
+COP2 118043Fh - 39 Cycles - NCCT - Normal Color Color (triple vector)
+COP2 0E80413h - 19 Cycles - NCDS - Normal color depth cue (single vector)
+COP2 0F80416h - 44 Cycles - NCDT - Normal color depth cue (triple vectors)
+In: V0=Normal vector (for triple variants repeated with V1 and V2),
+BK=Background color, RGBC=Primary color/code, LLM=Light matrix, LCM=Color
+matrix, IR0=Interpolation value.
+ [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] = (LLM*V0) SAR (sf*12)
+ [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] = (BK*1000h + LCM*IR) SAR (sf*12)
+ [MAC1,MAC2,MAC3] = [R*IR1,G*IR2,B*IR3] SHL 4 ;<--- for NCDx/NCCx
+ [MAC1,MAC2,MAC3] = MAC+(FC-MAC)*IR0 ;<--- for NCDx only
+ [MAC1,MAC2,MAC3] = [MAC1,MAC2,MAC3] SAR (sf*12) ;<--- for NCDx/NCCx
+ Color FIFO = [MAC1/16,MAC2/16,MAC3/16,CODE], [IR1,IR2,IR3] = [MAC1,MAC2,MAC3]
+
+COP2 138041Ch - 11 Cycles - CC(lm=1) - Color Color
+COP2 1280414h - 13 Cycles - CDP(...) - Color Depth Que
+In: [IR1,IR2,IR3]=Vector, RGBC=Primary color/code, LCM=Color matrix,
+BK=Background color, and, for CDP, IR0=Interpolation value, FC=Far color.
+ [IR1,IR2,IR3] = [MAC1,MAC2,MAC3] = (BK*1000h + LCM*IR) SAR (sf*12)
+ [MAC1,MAC2,MAC3] = [R*IR1,G*IR2,B*IR3] SHL 4
+ [MAC1,MAC2,MAC3] = MAC+(FC-MAC)*IR0 ;<--- for CDP only
+ [MAC1,MAC2,MAC3] = [MAC1,MAC2,MAC3] SAR (sf*12)
+ Color FIFO = [MAC1/16,MAC2/16,MAC3/16,CODE], [IR1,IR2,IR3] = [MAC1,MAC2,MAC3]
+
+COP2 0680029h - 8 Cycles - DCPL - Depth Cue Color light
+COP2 0780010h - 8 Cycles - DPCS - Depth Cueing (single)
+COP2 0x8002Ah - 17 Cycles - DPCT - Depth Cueing (triple)
+COP2 0980011h - 8 Cycles - INTPL - Interpolation of a vector and far color
+In: [IR1,IR2,IR3]=Vector, FC=Far Color, IR0=Interpolation value, CODE=MSB of
+RGBC, and, for DCPL, R,G,B=LSBs of RGBC.
+ [MAC1,MAC2,MAC3] = [R*IR1,G*IR2,B*IR3] SHL 4 ;<--- for DCPL only
+ [MAC1,MAC2,MAC3] = [IR1,IR2,IR3] SHL 12 ;<--- for INTPL only
+ [MAC1,MAC2,MAC3] = [R,G,B] SHL 16 ;<--- for DPCS/DPCT
+ [MAC1,MAC2,MAC3] = MAC+(FC-MAC)*IR0
+ [MAC1,MAC2,MAC3] = [MAC1,MAC2,MAC3] SAR (sf*12)
+ Color FIFO = [MAC1/16,MAC2/16,MAC3/16,CODE], [IR1,IR2,IR3] = [MAC1,MAC2,MAC3]
+DPCT executes thrice, and reads the R,G,B values from RGB0 (ie. reads from the
+Bottom of the Color FIFO, instead of from the RGBC register) (the CODE value is
+kept read from RGBC as usually), so, after DPCT execution, the RGB0,RGB1,RGB2
+Fifo entries are modified.
+
+COP2 190003Dh - 5 Cycles - GPF(sf,lm) - General purpose Interpolation
+COP2 1A0003Eh - 5 Cycles - GPL(sf,?) - General Interpolation with base
+ [MAC1,MAC2,MAC3] = [0,0,0] ;<--- for GPF only
+ [MAC1,MAC2,MAC3] = [MAC1,MAC2,MAC3] SHL (sf*12) ;<--- for GPL only
+ [MAC1,MAC2,MAC3] = (([IR1,IR2,IR3] * IR0) + [MAC1,MAC2,MAC3]) SAR (sf*12)
+ Color FIFO = [MAC1/16,MAC2/16,MAC3/16,CODE], [IR1,IR2,IR3] = [MAC1,MAC2,MAC3]
+Note: Although the SHL in GPL is theoretically undone by the SAR, 44bit
+overflows can occur internally when sf=1.
+
+Details on "MAC+(FC-MAC)*IR0"
+ [IR1,IR2,IR3] = (([RFC,GFC,BFC] SHL 12) - [MAC1,MAC2,MAC3]) SAR (sf*12)
+ [MAC1,MAC2,MAC3] = (([IR1,IR2,IR3] * IR0) + [MAC1,MAC2,MAC3])
+Note: Above "[IR1,IR2,IR3]=(FC-MAC)" is saturated to -8000h..+7FFFh (ie. as if
+lm=0), anyways, further writes to [IR1,IR2,IR3] (within the same command) are
+saturated as usually (ie. depending on lm setting).
+
+Details on "(LLM*V0) SAR (sf*12)" and "(BK*1000h + LCM*IR) SAR (sf*12)"
+Works like MVMVA command (see there), but with fixed Tx/Vx/Mx parameters, the
+sf/lm bits can be changed and do affect the results (although normally both
+bits should be set for use with color matrices).
+
+Notes
+The 8bit RGB values written to the top of Color Fifo are the 32bit MACn values
+divided by 16, and saturated to +00h..+FFh, and of course, the older Fifo
+entries are moved downwards. Note that, at the GPU side, the meaning of the RGB
+values depends on whether or not texture blending is used (for untextured
+polygons FFh is max brightness) (for texture blending FFh is double brightness
+and 80h is normal brightness).
+The 8bit CODE value is intended to contain a GP0(20h..7Fh) Rendering command,
+allowing to automatically merge the 8bit command number, with the 24bit color
+value.
+The IRGB/ORGB registers allow to convert between 48bit and 15bit RGB colors.
+Although the result of the commands in this chapter is written to the Color
+FIFO, some commands like GPF/GPL may be also used for other purposes (eg. to
+scale or scale/translate single vertices).
+
+GTE Division Inaccuracy
+-----------------------
+
+GTE Division Inaccuracy (for RTPS/RTPT commands)
+Basically, the GTE division does (attempt to) work as so (using 33bit maths):
+ n = (((H*20000h/SZ3)+1)/2)
+alternatly, below would give (almost) the same result (using 32bit maths):
+ n = ((H*10000h+SZ3/2)/SZ3)
+in both cases, the result is saturated about as so:
+ if n>1FFFFh or division_by_zero then n=1FFFFh, FLAG.Bit17=1, FLAG.Bit31=1
+However, the real GTE hardware is using a fast, but less accurate division
+mechanism (based on Unsigned Newton-Raphson (UNR) algorithm):
+ if (H < SZ3*2) then ;check if overflow
+ z = count_leading_zeroes(SZ3) ;z=0..0Fh (for 16bit SZ3)
+ n = (H SHL z) ;n=0..7FFF8000h
+ d = (SZ3 SHL z) ;d=8000h..FFFFh
+ u = unr_table[(d-7FC0h) SHR 7] + 101h ;u=200h..101h
+ d = ((2000080h - (d * u)) SHR 8) ;d=10000h..0FF01h
+ d = ((0000080h + (d * u)) SHR 8) ;d=20000h..10000h
+ n = min(1FFFFh, (((n*d) + 8000h) SHR 16)) ;n=0..1FFFFh
+ else n = 1FFFFh, FLAG.Bit17=1, FLAG.Bit31=1 ;n=1FFFFh plus overflow flag
+the GTE's unr_table[000h..100h] consists of following values:
+ FFh,FDh,FBh,F9h,F7h,F5h,F3h,F1h,EFh,EEh,ECh,EAh,E8h,E6h,E4h,E3h ;\
+ E1h,DFh,DDh,DCh,DAh,D8h,D6h,D5h,D3h,D1h,D0h,CEh,CDh,CBh,C9h,C8h ; 00h..3Fh
+ C6h,C5h,C3h,C1h,C0h,BEh,BDh,BBh,BAh,B8h,B7h,B5h,B4h,B2h,B1h,B0h ;
+ AEh,ADh,ABh,AAh,A9h,A7h,A6h,A4h,A3h,A2h,A0h,9Fh,9Eh,9Ch,9Bh,9Ah ;/
+ 99h,97h,96h,95h,94h,92h,91h,90h,8Fh,8Dh,8Ch,8Bh,8Ah,89h,87h,86h ;\
+ 85h,84h,83h,82h,81h,7Fh,7Eh,7Dh,7Ch,7Bh,7Ah,79h,78h,77h,75h,74h ; 40h..7Fh
+ 73h,72h,71h,70h,6Fh,6Eh,6Dh,6Ch,6Bh,6Ah,69h,68h,67h,66h,65h,64h ;
+ 63h,62h,61h,60h,5Fh,5Eh,5Dh,5Dh,5Ch,5Bh,5Ah,59h,58h,57h,56h,55h ;/
+ 54h,53h,53h,52h,51h,50h,4Fh,4Eh,4Dh,4Dh,4Ch,4Bh,4Ah,49h,48h,48h ;\
+ 47h,46h,45h,44h,43h,43h,42h,41h,40h,3Fh,3Fh,3Eh,3Dh,3Ch,3Ch,3Bh ; 80h..BFh
+ 3Ah,39h,39h,38h,37h,36h,36h,35h,34h,33h,33h,32h,31h,31h,30h,2Fh ;
+ 2Eh,2Eh,2Dh,2Ch,2Ch,2Bh,2Ah,2Ah,29h,28h,28h,27h,26h,26h,25h,24h ;/
+ 24h,23h,22h,22h,21h,20h,20h,1Fh,1Eh,1Eh,1Dh,1Dh,1Ch,1Bh,1Bh,1Ah ;\
+ 19h,19h,18h,18h,17h,16h,16h,15h,15h,14h,14h,13h,12h,12h,11h,11h ; C0h..FFh
+ 10h,0Fh,0Fh,0Eh,0Eh,0Dh,0Dh,0Ch,0Ch,0Bh,0Ah,0Ah,09h,09h,08h,08h ;
+ 07h,07h,06h,06h,05h,05h,04h,04h,03h,03h,02h,02h,01h,01h,00h,00h ;/
+ 00h ;<-- one extra table entry (for "(d-7FC0h)/80h"=100h) ;-100h
+Above can be generated as "unr_table[i]=min(0,(40000h/(i+100h)+1)/2-101h)".
+Some special cases: NNNNh/0001h uses a big multiplier (d=20000h), in practice,
+this can occur only for 0000h/0001h and 0001h/0001h (due to the H<SZ3*2
+overflow check).
+The min(1FFFFh) limit is needed for cases like FE3Fh/7F20h, F015h/780Bh, etc.
+(these do produce UNR result 20000h, and are saturated to 1FFFFh, but without
+setting overflow FLAG bits).
+
+Macroblock Decoder (MDEC)
+-------------------------
+
+The MDEC is a JPEG-style Macroblock Decoder, that can decompress pictures (or a
+series of pictures, for being displayed as a movie).
+
+--> MDEC I/O Ports
+--> MDEC Commands
+--> MDEC Decompression
+--> MDEC Data Format
+
+MDEC I/O Ports
+--------------
+
+1F801820h - MDEC0 - MDEC Command/Parameter Register (W)
+ 31-0 Command or Parameters
+Used to send command word, followed by parameter words to the MDEC (usually,
+only the command word is written to this register, and the parameter words are
+transferred via DMA0).
+
+1F801820h.Read - MDEC Data/Response Register (R)
+ 31-0 Macroblock Data (or Garbage if there's no data available)
+The data is always output as a 8x8 pixel bitmap, so, when manually reading from
+this register and using colored 16x16 pixel macroblocks, the data from four 8x8
+blocks must be re-ordered accordingly (usually, the data is received via DMA1,
+which is doing the re-ordering automatically). For monochrome 8x8 macroblocks,
+no re-ordering is needed (that works with DMA1, too).
+
+1F801824h - MDEC1 - MDEC Status Register (R)
+ 31 Data-Out Fifo Empty (0=No, 1=Empty)
+ 30 Data-In Fifo Full (0=No, 1=Full, or Last word received)
+ 29 Command Busy (0=Ready, 1=Busy receiving or processing parameters)
+ 28 Data-In Request (set when DMA0 enabled and ready to receive data)
+ 27 Data-Out Request (set when DMA1 enabled and ready to send data)
+ 26-25 Data Output Depth (0=4bit, 1=8bit, 2=24bit, 3=15bit) ;CMD.28-27
+ 24 Data Output Signed (0=Unsigned, 1=Signed) ;CMD.26
+ 23 Data Output Bit15 (0=Clear, 1=Set) (for 15bit depth only) ;CMD.25
+ 22-19 Not used (seems to be always zero)
+ 18-16 Current Block (0..3=Y1..Y4, 4=Cr, 5=Cb) (or for mono: always 4=Y)
+ 15-0 Number of Parameter Words remaining minus 1 (FFFFh=None) ;CMD.Bit0-15
+If there's data in the output fifo, then the Current Block bits are always set
+to the current output block number (ie. Y1..Y4; or Y for mono) (this
+information is apparently passed to the DMA1 controller, so that it knows if
+and how it must re-order the data in RAM). If the output fifo is empty, then
+the bits indicate the currently processsed incoming block (ie. Cr,Cb,Y1..Y4; or
+Y for mono).
+
+1F801824h - MDEC1 - MDEC Control/Reset Register (W)
+ 31 Reset MDEC (0=No change, 1=Abort any command, and set status=80040000h)
+ 30 Enable Data-In Request (0=Disable, 1=Enable DMA0 and Status.bit28)
+ 29 Enable Data-Out Request (0=Disable, 1=Enable DMA1 and Status.bit27)
+ 28-0 Unknown/Not used - usually zero
+The data requests are required to be enabled for using DMA (and for reading the
+request status flags by software). The Data-Out request acts a bit strange: It
+gets set when a block is available, but, it gets cleared after reading the
+first some words of that block (nethertheless, one can keep reading the whole
+block, until the fifo-empty flag gets set).
+
+DMA
+MDEC decompression uses a lot of DMA channels (and CPU processing):
+ 1) DMA3 (CDROM) to send Huffman compressed data from CDROM to RAM
+ 2) CPU (MIPS) to convert Huffman bitstream to 16bit MDEC RLE values
+ 3) DMA0 (MDEC.In) to send MDEC compressed data from RAM to MDEC
+ 4) DMA1 (MDEC.Out) to send uncompressed macroblocks from MDEC to RAM
+ 5) DMA2 (GPU) to send uncompressed macroblocks from RAM to GPU
+DMA0 and DMA1 should be usually used with a blocksize of 20h words. If
+necessary, the parameters for the MDEC(1) command should be padded with FE00h
+halfwords to match the 20h words (40h halfwords) DMA blocksize.
+
+MDEC Commands
+-------------
+
+MDEC(1) - Decode Macroblock(s)
+ 31-29 Command (1=decode_macroblock)
+ 28-27 Data Output Depth (0=4bit, 1=8bit, 2=24bit, 3=15bit) ;STAT.26-25
+ 26 Data Output Signed (0=Unsigned, 1=Signed) ;STAT.24
+ 25 Data Output Bit15 (0=Clear, 1=Set) (for 15bit depth only) ;STAT.23
+ 24-16 Not used (should be zero)
+ 15-0 Number of Parameter Words (size of compressed data)
+This command is followed by one or more Macroblock parameters (usually, all
+macroblocks for the whole image are sent at once).
+
+MDEC(2) - Set Quant Table(s)
+ 31-29 Command (2=set_iqtab)
+ 28-1 Not used (should be zero) ;Bit25-28 are copied to STAT.23-26 though
+ 0 Color (0=Luminance only, 1=Luminance and Color)
+The command word is followed by 64 unsigned parameter bytes for the Luminance
+Quant Table (used for Y1..Y4), and if Command.Bit0 was set, by another 64
+unsigned parameter bytes for the Color Quant Table (used for Cr and Cb).
+
+MDEC(3) - Set Scale Table
+ 31-29 Command (3=set_scale)
+ 28-0 Not used (should be zero) ;Bit25-28 are copied to STAT.23-26 though
+The command is followed by 64 signed halfwords with 14bit fractional part, the
+values should be usually/always the same values (based on the standard JPEG
+constants, although, MDEC(3) allows to use other values than that constants).
+
+MDEC(0) - No function
+This command has no function. Command bits 25-28 are reflected to Status bits
+23-26 as usually. Command bits 0-15 are reflected to Status bits 0-15 (similar
+as the "number of parameter words" for MDEC(1), but without the "minus 1"
+effect, and without actually expecting any parameters).
+
+MDEC(4..7) - Invalid
+These commands act identical as MDEC(0).
+
+MDEC Decompression
+------------------
+
+decode_colored_macroblock ;MDEC(1) command (at 15bpp or 24bpp depth)
+ rl_decode_block(Crblk,src,iq_uv) ;Cr (low resolution)
+ rl_decode_block(Cbblk,src,iq_uv) ;Cb (low resolution)
+ rl_decode_block(Yblk,src,iq_y), yuv_to_rgb(0,0) ;Y1 (and upper-left Cr,Cb)
+ rl_decode_block(Yblk,src,iq_y), yuv_to_rgb(0,8) ;Y2 (and upper-right Cr,Cb)
+ rl_decode_block(Yblk,src,iq_y), yuv_to_rgb(8,0) ;Y3 (and lower-left Cr,Cb)
+ rl_decode_block(Yblk,src,iq_y), yuv_to_rgb(8,8) ;Y4 (and lower-right Cr,Cb)
+
+decode_monochrome_macroblock ;MDEC(1) command (at 4bpp or 8bpp depth)
+ rl_decode_block(Yblk,src,iq_y), y_to_mono ;Y
+
+rl_decode_block(blk,src,qt)
+ for i=0 to 63, blk[i]=0, next i ;initially zerofill all entries (for skip)
+ @@skip:
+ n=[src], src=src+2, k=0 ;get first entry, init dest addr k=0
+ if n=FE00h then @@skip ;ignore padding (FE00h as first halfword)
+ q_scale=(n SHR 10) AND 3Fh ;contains scale value (not "skip" value)
+ val=signed10bit(n AND 3FFh)*qt[k] ;calc first value (without q_scale/8) (?)
+ @@lop:
+ if q_scale=0 then val=signed10bit(n AND 3FFh)*2 ;special mode without qt[k]
+ val=minmax(val,-400h,+3FFh) ;saturate to signed 11bit range
+ val=val*scalezag[i] ;<-- for "fast_idct_core" only
+ if q_scale>0 then blk[zagzig[k]]=val ;store entry (normal case)
+ if q_scale=0 then blk[k]=val ;store entry (special, no zigzag)
+ n=[src], src=src+2 ;get next entry (or FE00h end code)
+ k=k+((n SHR 10) AND 3Fh)+1 ;skip zerofilled entries
+ val=(signed10bit(n AND 3FFh)*qt[k]*q_scale+4)/8 ;calc value for next entry
+ if k<=63 then jump @@lop ;should end with n=FE00h (that sets k>63)
+ idct_core(blk)
+ return (with "src" address advanced)
+
+fast_idct_core(blk) ;fast "idct_core" version
+Fast code with only 80 multiplications, works only if the scaletable from
+MDEC(3) command contains standard values (which is the case for all known PSX
+games).
+ src=blk, dst=temp_buffer
+ for pass=0 to 1
+ for i=0 to 7
+ if src[(1..7)*8+i]=0 then ;when src[(1..7)*8+i] are all zero:
+ dst[i*8+(0..7)]=src[0*8+i] ;quick fill by src[0*8+i]
+ else
+ z10=src[0*8+i]+src[4*8+i], z11=src[0*8+i]-src[4*8+i]
+ z13=src[2*8+i]+src[6*8+i], z12=src[2*8+i]-src[6*8+i]
+ z12=(1.414213562*z12)-z13 ;=sqrt(2)
+ tmp0=z10+z13, tmp3=z10-z13, tmp1=z11+z12, tmp2=z11-z12
+ z13=src[3*8+i]+src[5*8+i], z10=src[3*8+i]-src[5*8+i]
+ z11=src[1*8+i]+src[7*8+i], z12=src[1*8+i]-src[7*8+i]
+ z5 =(1.847759065*(z12-z10)) ;=sqrt(2)*scalefactor[2]
+ tmp7=z11+z13
+ tmp6=(2.613125930*(z10))+z5-tmp7 ;=scalefactor[2]*2
+ tmp5=(1.414213562*(z11-z13))-tmp6 ;=sqrt(2)
+ tmp4=(1.082392200*(z12))-z5+tmp5 ;=sqrt(2)/scalefactor[2]
+ dst[i*8+0]=tmp0+tmp7, dst[i*8+7]=tmp0-tmp7
+ dst[i*8+1]=tmp1+tmp6, dst[i*8+6]=tmp1-tmp6
+ dst[i*8+2]=tmp2+tmp5, dst[i*8+5]=tmp2-tmp5
+ dst[i*8+4]=tmp3+tmp4, dst[i*8+3]=tmp3-tmp4
+ endif
+ next i
+ swap(src,dst)
+ next pass
+
+real_idct_core(blk) ;low level "idct_core" version
+Low level code with 1024 multiplications, using the scaletable from the MDEC(3)
+command. Computes dst=src*scaletable (using normal matrix maths, but with "src"
+being diagonally mirrored, ie. the matrices are processed column by column,
+instead of row by column), repeated with src/dst exchanged.
+ src=blk, dst=temp_buffer
+ for pass=0 to 1
+ for x=0 to 7
+ for y=0 to 7
+ sum=0
+ for z=0 to 7
+ sum=sum+src[y+z*8]*(scaletable[x+z*8]/8)
+ next z
+ dst[x+y*8]=(sum+0fffh)/2000h ;<-- or so?
+ next y
+ next x
+ swap(src,dst)
+ next pass
+The "(sum+0fffh)/2000h" part is meant to strip fractional bits, and to round-up
+the result if the fraction was BIGGER than 0.5. The hardware appears to be
+working roughly like that, still the results aren't perfect.
+Maybe the real hardware is doing further roundings in other places, possibly
+stripping some fractional bits before summing up "sum", possibly stripping
+different amounts of bits in the two "pass" cycles, and possibly keeping a
+final fraction passed on to the y_to_mono stage.
+
+yuv_to_rgb(xx,yy)
+ for y=0 to 7
+ for x=0 to 7
+ R=[Crblk+((x+xx)/2)+((y+yy)/2)*8], B=[Cbblk+((x+xx)/2)+((y+yy)/2)*8]
+ G=(-0.3437*B)+(-0.7143*R), R=(1.402*R), B=(1.772*B)
+ Y=[Yblk+(x)+(y)*8]
+ R=MinMax(-128,127,(Y+R))
+ G=MinMax(-128,127,(Y+G))
+ B=MinMax(-128,127,(Y+B))
+ if unsigned then BGR=BGR xor 808080h ;aka add 128 to the R,G,B values
+ dst[(x+xx)+(y+yy)*16]=BGR
+ next x
+ next y
+Note: The exact fixed point resolution for "yuv_to_rgb" is unknown. And,
+there's probably also some 9bit limit (similar as in "y_to_mono").
+
+y_to_mono
+ for i=0 to 63
+ Y=[Yblk+i]
+ Y=Y AND 1FFh ;clip to signed 9bit range
+ Y=MinMax(-128,127,Y) ;saturate from 9bit to signed 8bit range
+ if unsigned then Y=Y xor 80h ;aka add 128 to the Y value
+ dst[i]=Y
+ next i
+
+set_iqtab ;MDEC(2) command
+ iqtab_core(iq_y,src), src=src+64 ;luminance quant table
+ if command_word.bit0=1
+ iqtab_core(iq_uv,src), src=src+64 ;color quant table (optional)
+ endif
+
+iqtab_core(iq,src) ;src = 64 unsigned paramter bytes
+ for i=0 to 63, iq[i]=src[i], next i
+Note: For "fast_idct_core" one could precalc "iq[i]=src[i]*scalezag[i]", but
+that would conflict with the RLE saturation/rounding steps (though those steps
+aren't actually required, so a very-fast decoder could omit them).
+
+scalefactor[0..7] = cos((0..7)*90'/8) ;for [1..7]: multiplied by sqrt(2)
+ 1.000000000, 1.387039845, 1.306562965, 1.175875602,
+ 1.000000000, 0.785694958, 0.541196100, 0.275899379
+
+zigzag[0..63] =
+ 0 ,1 ,5 ,6 ,14,15,27,28,
+ 2 ,4 ,7 ,13,16,26,29,42,
+ 3 ,8 ,12,17,25,30,41,43,
+ 9 ,11,18,24,31,40,44,53,
+ 10,19,23,32,39,45,52,54,
+ 20,22,33,38,46,51,55,60,
+ 21,34,37,47,50,56,59,61,
+ 35,36,48,49,57,58,62,63
+
+scalezag[0..63] (precalulated factors, for "fast_idct_core")
+ for y=0 to 7
+ for x=0 to 7
+ scalezag[zigzag[x+y*8]] = scalefactor[x] * scalefactor[y] / 8
+ next x
+ next y
+
+zagzig[0..63] (reversed zigzag table)
+ for i=0 to 63, zagzig[zigzag[i]]=i, next i
+
+set_quant_table: ;MDEC(2) command
+This command defines the quant tables, there are two tables (one for luminance
+and one for chroma). For STR movies and BS pictures both 64-byte tables should
+be almost always set to following 64 bytes:
+ 02h,10h,10h,13h,10h,13h,16h,16h
+ 16h,16h,16h,16h,1Ah,18h,1Ah,1Bh
+ 1Bh,1Bh,1Ah,1Ah,1Ah,1Ah,1Bh,1Bh
+ 1Bh,1Dh,1Dh,1Dh,22h,22h,22h,1Dh
+ 1Dh,1Dh,1Bh,1Bh,1Dh,1Dh,20h,20h
+ 22h,22h,25h,26h,25h,23h,23h,22h
+ 23h,26h,26h,28h,28h,28h,30h,30h
+ 2Eh,2Eh,38h,38h,3Ah,45h,45h,53h
+Note: The exception are BS fraquant movies in X-Files and Eagle One (these do
+also use the above values, but do have them multiplied with a fixed point
+number).
+
+set_scale_table: ;MDEC(3) command
+This command defines the IDCT scale matrix, which should be usually/always:
+ 5A82 5A82 5A82 5A82 5A82 5A82 5A82 5A82
+ 7D8A 6A6D 471C 18F8 E707 B8E3 9592 8275
+ 7641 30FB CF04 89BE 89BE CF04 30FB 7641
+ 6A6D E707 8275 B8E3 471C 7D8A 18F8 9592
+ 5A82 A57D A57D 5A82 5A82 A57D A57D 5A82
+ 471C 8275 18F8 6A6D 9592 E707 7D8A B8E3
+ 30FB 89BE 7641 CF04 CF04 7641 89BE 30FB
+ 18F8 B8E3 6A6D 8275 7D8A 9592 471C E707
+Note that the hardware does actually use only the upper 13bit of those 16bit
+values. The values are choosen like so,
+ +s0 +s0 +s0 +s0 +s0 +s0 +s0 +s0
+ +s1 +s3 +s5 +s7 -s7 -s5 -s3 -s1
+ +s2 +s6 -s6 -s2 -s2 -s6 +s6 +s2
+ +s3 -s7 -s1 -s5 +s5 +s1 +s7 -s3
+ +s4 -s4 -s4 +s4 +s4 -s4 -s4 +s4
+ +s5 -s1 +s7 +s3 -s3 -s7 +s1 -s5
+ +s6 -s2 +s2 -s6 -s6 +s2 -s2 +s6
+ +s7 -s5 +s3 -s1 +s1 -s3 +s5 -s7
+whereas, s0..s7 = scalefactor[0..7], multiplied by sqrt(2) (ie. by 1.414), and
+multiplied by 4000h (ie. with 14bit fractional part).
+
+MDEC Data Format
+----------------
+
+Colored Macroblocks (16x16 pixels) (in 15bpp or 24bpp depth mode)
+Each macroblock consists of six blocks: Two low-resolution blocks with color
+information (Cr,Cb) and four full-resolution blocks with luminance (grayscale)
+information (Y1,Y2,Y3,Y4). The color blocks are zoomed from 8x8 to 16x16 pixel
+size, merged with the luminance blocks, and then converted from YUV to RGB
+format.
+ .-----. .-----. .-----. .-----.
+ | | | | |Y1|Y2| | |
+ | Cr | + | Cb | + |--+--| ----> | RGB |
+ | | | | |Y3|Y4| | |
+ '-----' '-----' '-----' '-----'
+Native PSX files are usually containing vertically arranged Macroblocks (eg.
+allowing to send them to the GPU as 16x240 portion) (JPEG-style horizontally
+arranged Macroblocks would require to send the data in 16x16 pixel portions to
+the GPU) (something like 320x16 won't work, since that'd require to wrap from
+the bottom of the first macroblock to the top of the next macroblock).
+
+Monochrome Macroblocks (8x8 pixel) (in 4bpp or 8bpp depth mode)
+Each macroblock consist of only one block: with luminance (grayscale)
+information (Y), the data comes out as such (it isn't converted to RGB).
+ .--. .--.
+ |Y | ----> |Y |
+ '--' '--'
+The output is an 8x8 bitmap (not 16x16), so it'd be send to the GPU as 8x8
+pixel rectangle, or multiple blocks at once as 8x240 pixel rectangle. Since the
+data isn't RGB, it should be written to Texture memory (and then it can be
+forwarded to the frame buffer in form of a texture with monochrome 15bit
+palette with 32 grayscales). Alternately, one could convert the 8bpp image to
+24bpp by software (this would allow to use 256 grayscales).
+
+Blocks (8x8 pixels)
+An (uncompressed) block consists of 64 values, representing 8x8 pixels. The
+first (upper-left) value is an absolute value (called "DC" value), the
+remaining 63 values are relative to the DC value (called "AC" values). After
+decompression and zig-zag reordering, the data in unfiltered horizontally and
+vertically (IDCT conversion, ie. the relative "AC" values are converted to
+absolute "DC" values).
+
+.STR Files
+PSX Video files are usually having file extension .STR (for "Streaming").
+--> CDROM File Video STR Streaming and BS Picture Compression (Sony)
+
+MDEC vs JPEG
+The MDEC data format is very similar to the JPEG file format, the main
+difference is that JPEG uses Huffman compressed blocks, whilst MDEC uses
+Run-Length (RL) compressed blocks.
+The (uncompressed) blocks are same as in JPEGs, using the same zigzag ordering,
+AC to DC conversion, and YUV to RGB conversion (ie. the MDEC hardware can be
+also used to decompress JPEGs, when handling the file header and huffman
+decompression by software).
+Some other differences are that MDEC has only 2 fixed-purpose quant tables,
+whilst JPEGs <can> use up to 4 general-purpose quant tables. Also, JPEGs <can>
+use other color resolutions than the 8x8 color info for 16x16 pixels. Whereas,
+JPEGs <can> do that stuff, but most standard JPEG files aren't actually using 4
+quant tables, nor higher color resolution.
+
+Run-Length compressed Blocks
+Within each block the DCT information and RLE compressed data is stored:
+ DCT ;1 halfword
+ RLE,RLE,RLE,etc. ;0..63 halfwords
+ EOB ;1 halfword
+
+DCT (1st value)
+DCT data has the quantization factor and the Direct Current (DC) reference.
+ 15-10 Q Quantization factor (6 bits, unsigned)
+ 9-0 DC Direct Current reference (10 bits, signed)
+Contains the absolute DC value (the upper-left value of the 8x8 block).
+
+RLE (Run length data, for 2nd through 64th value)
+ 15-10 LEN Number of zero AC values to be inserted (6 bits, unsigned)
+ 9-0 AC Relative AC value (10 bits, signed)
+Example: AC values "000h,000h,123h" would be compressed as "(2 shl 10)+123h".
+
+EOB (End Of Block)
+Indicates the end of a 8x8 pixel block, causing the rest of the block to be
+padded with zero AC values.
+ 15-0 End-code (Fixed, FE00h)
+EOB isn't required if the block was already fully defined (up to including
+blk[63]), however, most games seem to append EOB to all blocks (although it's
+just acting as dummy/padding value in case of fully defined blocks).
+
+Dummy halfwords
+Data is sent in units of words (or, when using DMA, even in units of 32-words),
+which is making it neccessary to send some dummy halfwords (unless the
+compressed data size should match up the transfer unit). The value FE00h can be
+used as dummy value: When FE00h appears at the begin of a new block, or after
+the end of block, then it is simply ignored by the hardware (if it occurs
+elsewhere, then it acts as EOB end code, as described above).
+
+Sound Processing Unit (SPU)
+---------------------------
+
+--> SPU Overview
+--> SPU ADPCM Samples
+--> SPU ADPCM Pitch
+--> SPU Volume and ADSR Generator
+--> SPU Voice Flags
+--> SPU Noise Generator
+--> SPU Control and Status Register
+--> SPU Memory Access
+--> SPU Interrupt
+--> SPU Reverb Registers
+--> SPU Reverb Formula
+--> SPU Reverb Examples
+--> SPU Unknown Registers
+
+SPU Overview
+------------
+
+SPU I/O Port Summary
+ 1F801C00h..1F801D7Fh - Voice 0..23 Registers (eight 16bit regs per voice)
+ 1F801D80h..1F801D87h - SPU Control (volume)
+ 1F801D88h..1F801D9Fh - Voice 0..23 Flags (six 1bit flags per voice)
+ 1F801DA2h..1F801DBFh - SPU Control (memory, control, etc.)
+ 1F801DC0h..1F801DFFh - Reverb configuration area
+ 1F801E00h..1F801E5Fh - Voice 0..23 Internal Registers
+ 1F801E60h..1F801E7Fh - Unknown?
+ 1F801E80h..1F801FFFh - Unused?
+
+SPU Memory layout (512Kbyte RAM)
+ 00000h-003FFh CD Audio left (1Kbyte) ;\CD Audio before Volume processing
+ 00400h-007FFh CD Audio right (1Kbyte) ;/signed 16bit samples at 44.1kHz
+ 00800h-00BFFh Voice 1 mono (1Kbyte) ;\Voice 1 and 3 after ADSR processing
+ 00C00h-00FFFh Voice 3 mono (1Kbyte) ;/signed 16bit samples at 44.1kHz
+ 01000h-xxxxxh ADPCM Samples (first 16bytes usually contain a Sine wave)
+ xxxxxh-7FFFFh Reverb work area
+As shown above, the first 4Kbytes are used as special capture buffers, and, if
+desired, one can also use the Reverb hardware to capture output from other
+voice(s).
+The SPU memory is not mapped to the CPU bus, it can be accessed only via I/O,
+or via DMA transfers (DMA4).
+
+Voices
+The SPU has 24 hardware voices. These voices can be used to reproduce sample
+data, noise or can be used as frequency modulator on the next voice. Each voice
+has it's own programmable ADSR envelope filter. The main volume can be
+programmed independently for left and right output.
+
+Voice Capabilities
+All 24 voices are having exactly the same capabilities(?), with the exception
+that Voice 1 and 3 are having a special Capture feature (see SPU Memory map).
+There seems to be no way to produce square waves (without storing a square
+wavefrom in memory... although, since SPU RAM isn't connected to the CPU bus,
+the "useless" DMA for square wave data wouldn't slowdown the CPU bus)?
+
+Additional Sound Inputs
+External Audio can be input (from the Expansion Port?), and the CDROM drive can
+be commanded to playback normal Audio CDs (via Play command), or XA-ADPCM
+sectors (via Read command), and to pass that data to the SPU.
+
+Unstable and Delayed I/O
+The SPU occassionally seems to "miss" I/O writes (not sure if that can be fixed
+by any Memory Control settings?), a stable workaround is too write all values
+twice (except of course, Fifo writes). The SPU seems to process written values
+at 44100Hz rate (so it may take 1/44100 seconds (300h clock cycles) until it
+has actually realized the new value).
+
+Mono/Stereo Audio Output
+The standard PSX Audio cables have separate Left/Right signals, that is good
+for stereo TVs, but, when using a normal mono TV, only one of the two audio
+signals (Left or Right) can be connected. PSX programs should thus offer an
+option to disable stereo effects, and to output an equal volume to both cables.
+
+SPU Bus-Width
+The SPU is connected to a 16bit databus. 8bit/16bit/32bit reads and 16bit/32bit
+writes are implemented. However, 8bit writes are NOT implemented: 8bit writes
+to ODD addresses are simply ignored (without causing any exceptions), 8bit
+writes to EVEN addresses are executed as 16bit writes (eg. "movp r1,12345678h,
+movb [spu_port],r1" will write 5678h instead of 78h).
+
+SPU ADPCM Samples
+-----------------
+
+The SPU supports only ADPCM compressed samples (uncompressed samples seem to be
+totally unsupported; leaving apart that one can write uncompressed 16bit PCM
+samples to the Reverb Buffer, which can be then output at 22050Hz, as long as
+they aren't overwritten by the hardware).
+
+1F801C06h+N*10h - Voice 0..23 ADPCM Start Address (R/W)
+This register holds the sample start address (not the current address, ie. the
+register doesn't increment during playback).
+ 15-0 Startaddress of sound in Sound buffer (in 8-byte units)
+Writing to this register has no effect on the currently playing voice.
+The start address is copied to the current address upon Key On.
+
+1F801C0Eh+N*10h - Voice 0..23 ADPCM Repeat Address (R/W)
+If the hardware finds an ADPCM header with Loop-Start-Bit, then it copies the
+current address to the repeat addresss register.
+If the hardware finds an ADPCM header with Loop-Stop-Bit, then it copies the
+repeat addresss register setting to the current address; that, <after> playing
+the current ADPCM block.
+ 15-0 Address sample loops to at end (in 8-byte units)
+Normally, repeat works automatically via the above start/stop bits, and
+software doesn't need to deal with the Repeat Address Register. However,
+reading from it may be useful to sense if the hardware has reached a start bit,
+and writing may be also useful in some cases, eg. to redirect a one-shot sample
+(with stop-bit, but without any start-bits) to a silent-loop located elsewhere
+in memory.
+
+Sample Data (SPU-ADPCM)
+Samples consist of one or more 16-byte blocks:
+ 00h Shift/Filter (reportedly same as for CDROM XA-ADPCM) (see there)
+ 01h Flag Bits (see below)
+ 02h Compressed Data (LSBs=1st Sample, MSBs=2nd Sample)
+ 03h Compressed Data (LSBs=3rd Sample, MSBs=4th Sample)
+ 04h Compressed Data (LSBs=5th Sample, MSBs=6th Sample)
+ ... ...
+ 0Fh Compressed Data (LSBs=27th Sample, MSBs=28th Sample)
+
+Flag Bits (in 2nd byte of ADPCM Header)
+ 0 Loop End (0=No change, 1=Set ENDX flag and Jump to [1F801C0Eh+N*10h])
+ 1 Loop Repeat (0=Force Release and set ADSR Level to Zero; only if Bit0=1)
+ 2 Loop Start (0=No change, 1=Copy current address to [1F801C0Eh+N*10h])
+ 3-7 Unknown (usually 0)
+Possible combinations for Bit0-1 are:
+ Code 0 = Normal (continue at next 16-byte block)
+ Code 1 = End+Mute (jump to Loop-address, set ENDX flag, Release, Env=0000h)
+ Code 2 = Ignored (same as Code 0)
+ Code 3 = End+Repeat (jump to Loop-address, set ENDX flag)
+
+Looped and One-shot Samples
+The Loop Start/End flags in the ADPCM Header allow to play one or more sample
+block(s) in a loop, that can be either all block(s) endless repeated, or only
+the last some block(s) of the sample.
+There's no way to stop the output, so a one-shot sample must be followed by
+dummy block (with Loop Start/End flags both set, and all data nibbles set to
+zero; so that the block gets endless repeated, but doesn't produce any sound).
+
+SPU-ADPCM vs XA-ADPCM
+The PSX supports two ADPCM formats: SPU-ADPCM (as described above), and
+XA-ADPCM. XA-ADPCM is decompressed by the CDROM Controller, and sent directly
+to the sound mixer, without needing to store the data in SPU RAM, nor needing
+to use a Voice channel.
+The actual decompression algorithm is the same for both formats. However, the
+XA nibbles are arranged in different order, and XA uses 2x28 nibbles per block
+(instead of 2x14), XA blocks can contain mono or stereo data, XA supports only
+two sample rates, and, XA doesn't support looping.
+
+SPU ADPCM Pitch
+---------------
+
+1F801C04h+N*10h - Voice 0..23 ADPCM Sample Rate (R/W) (VxPitch)
+ 0-15 Sample rate (0=stop, 4000h=fastest, 4001h..FFFFh=usually same as 4000h)
+Defines the ADPCM sample rate (1000h = 44100Hz). This register (and PMON) does
+only affect the ADPCM sample frequency (but not the Noise frequency, which is
+defined - and shared for all voices - in the SPUCNT register).
+
+1F801D90h - Voice 0..23 Pitch Modulation Enable Flags (PMON)
+Pitch modulation allows to generate "Frequency Sweep" effects by mis-using the
+amplitude from channel (x-1) as pitch factor for channel (x).
+ 0 Unknown... Unused?
+ 1-23 Flags for Voice 1..23 (0=Normal, 1=Modulate by Voice 0..22)
+ 24-31 Not used
+For example, output a very loud 1Hz sine-wave on channel 4 (with ADSR volume
+4000h, and with Left/Right volume=0; unless you actually want to output it to
+the speaker). Then additionally output a 2kHz sine wave on channel 5 with
+PMON.Bit5 set. The "2kHz" sound should then repeatedly sweep within 1kHz..3kHz
+range (or, for a more decent sweep in 1.8kHz..2.2kHz range, drop the ADSR
+volume of channel 4).
+
+Pitch Counter
+The pitch counter is adjusted at 44100Hz rate as follows:
+ Step = VxPitch ;range +0000h..+FFFFh (0...705.6 kHz)
+ IF PMON.Bit(x)=1 AND (x>0) ;pitch modulation enable
+ Factor = VxOUTX(x-1) ;range -8000h..+7FFFh (prev voice amplitude)
+ Factor = Factor+8000h ;range +0000h..+FFFFh (factor = 0.00 .. 1.99)
+ Step=SignExpand16to32(Step) ;hardware glitch on VxPitch>7FFFh, make sign
+ Step = (Step * Factor) SAR 15 ;range 0..1FFFFh (glitchy if VxPitch>7FFFh)
+ Step=Step AND 0000FFFFh ;hardware glitch on VxPitch>7FFFh, kill sign
+ IF Step>3FFFh then Step=4000h ;range +0000h..+3FFFh (0.. 176.4kHz)
+ Counter = Counter + Step
+Counter.Bit12 and up indicates the current sample (within a ADPCM block).
+Counter.Bit3..11 are used as 8bit gaussian interpolation index.
+
+Maximum Sound Frequency
+The Mixer and DAC supports a 44.1kHz output rate (allowing to produce max
+22.1kHz tones). The Reverb unit supports only half the frequency.
+The pitch counter supports sample rates up to 176.4kHz. However, exceeding the
+44.1kHz limit causes the hardware to skip samples (or actually: to apply
+incomplete interpolation on the 'skipped' samples).
+VxPitch can be theoretically 0..FFFFh (max 705.6kHz), normally 4000h..FFFFh are
+simply clipped to max=4000h (176.4kHz). Except, 4000h..FFFFh could be used with
+pitch modulation (as they are multiplied by 0.00..1.99 before clipping; in
+practice this works only for 4000h..7FFFh; as values 8000h..FFFFh are mistaken
+as signed values).
+
+4-Point Gaussian Interpolation
+Interpolation is applied on the 4 most recent 16bit ADPCM samples
+(new,old,older,oldest), using bit4-11 of the pitch counter as 8bit
+interpolation index (i=00h..FFh):
+ out = ((gauss[0FFh-i] * oldest) SAR 15)
+ out = out + ((gauss[1FFh-i] * older) SAR 15)
+ out = out + ((gauss[100h+i] * old) SAR 15)
+ out = out + ((gauss[000h+i] * new) SAR 15)
+The Gauss table contains the following values (in hex):
+ -001h,-001h,-001h,-001h,-001h,-001h,-001h,-001h ;\
+ -001h,-001h,-001h,-001h,-001h,-001h,-001h,-001h ;
+ 0000h,0000h,0000h,0000h,0000h,0000h,0000h,0001h ;
+ 0001h,0001h,0001h,0002h,0002h,0002h,0003h,0003h ;
+ 0003h,0004h,0004h,0005h,0005h,0006h,0007h,0007h ;
+ 0008h,0009h,0009h,000Ah,000Bh,000Ch,000Dh,000Eh ;
+ 000Fh,0010h,0011h,0012h,0013h,0015h,0016h,0018h ; entry
+ 0019h,001Bh,001Ch,001Eh,0020h,0021h,0023h,0025h ; 000h..07Fh
+ 0027h,0029h,002Ch,002Eh,0030h,0033h,0035h,0038h ;
+ 003Ah,003Dh,0040h,0043h,0046h,0049h,004Dh,0050h ;
+ 0054h,0057h,005Bh,005Fh,0063h,0067h,006Bh,006Fh ;
+ 0074h,0078h,007Dh,0082h,0087h,008Ch,0091h,0096h ;
+ 009Ch,00A1h,00A7h,00ADh,00B3h,00BAh,00C0h,00C7h ;
+ 00CDh,00D4h,00DBh,00E3h,00EAh,00F2h,00FAh,0101h ;
+ 010Ah,0112h,011Bh,0123h,012Ch,0135h,013Fh,0148h ;
+ 0152h,015Ch,0166h,0171h,017Bh,0186h,0191h,019Ch ;/
+ 01A8h,01B4h,01C0h,01CCh,01D9h,01E5h,01F2h,0200h ;\
+ 020Dh,021Bh,0229h,0237h,0246h,0255h,0264h,0273h ;
+ 0283h,0293h,02A3h,02B4h,02C4h,02D6h,02E7h,02F9h ;
+ 030Bh,031Dh,0330h,0343h,0356h,036Ah,037Eh,0392h ;
+ 03A7h,03BCh,03D1h,03E7h,03FCh,0413h,042Ah,0441h ;
+ 0458h,0470h,0488h,04A0h,04B9h,04D2h,04ECh,0506h ;
+ 0520h,053Bh,0556h,0572h,058Eh,05AAh,05C7h,05E4h ; entry
+ 0601h,061Fh,063Eh,065Ch,067Ch,069Bh,06BBh,06DCh ; 080h..0FFh
+ 06FDh,071Eh,0740h,0762h,0784h,07A7h,07CBh,07EFh ;
+ 0813h,0838h,085Dh,0883h,08A9h,08D0h,08F7h,091Eh ;
+ 0946h,096Fh,0998h,09C1h,09EBh,0A16h,0A40h,0A6Ch ;
+ 0A98h,0AC4h,0AF1h,0B1Eh,0B4Ch,0B7Ah,0BA9h,0BD8h ;
+ 0C07h,0C38h,0C68h,0C99h,0CCBh,0CFDh,0D30h,0D63h ;
+ 0D97h,0DCBh,0E00h,0E35h,0E6Bh,0EA1h,0ED7h,0F0Fh ;
+ 0F46h,0F7Fh,0FB7h,0FF1h,102Ah,1065h,109Fh,10DBh ;
+ 1116h,1153h,118Fh,11CDh,120Bh,1249h,1288h,12C7h ;/
+ 1307h,1347h,1388h,13C9h,140Bh,144Dh,1490h,14D4h ;\
+ 1517h,155Ch,15A0h,15E6h,162Ch,1672h,16B9h,1700h ;
+ 1747h,1790h,17D8h,1821h,186Bh,18B5h,1900h,194Bh ;
+ 1996h,19E2h,1A2Eh,1A7Bh,1AC8h,1B16h,1B64h,1BB3h ;
+ 1C02h,1C51h,1CA1h,1CF1h,1D42h,1D93h,1DE5h,1E37h ;
+ 1E89h,1EDCh,1F2Fh,1F82h,1FD6h,202Ah,207Fh,20D4h ;
+ 2129h,217Fh,21D5h,222Ch,2282h,22DAh,2331h,2389h ; entry
+ 23E1h,2439h,2492h,24EBh,2545h,259Eh,25F8h,2653h ; 100h..17Fh
+ 26ADh,2708h,2763h,27BEh,281Ah,2876h,28D2h,292Eh ;
+ 298Bh,29E7h,2A44h,2AA1h,2AFFh,2B5Ch,2BBAh,2C18h ;
+ 2C76h,2CD4h,2D33h,2D91h,2DF0h,2E4Fh,2EAEh,2F0Dh ;
+ 2F6Ch,2FCCh,302Bh,308Bh,30EAh,314Ah,31AAh,3209h ;
+ 3269h,32C9h,3329h,3389h,33E9h,3449h,34A9h,3509h ;
+ 3569h,35C9h,3629h,3689h,36E8h,3748h,37A8h,3807h ;
+ 3867h,38C6h,3926h,3985h,39E4h,3A43h,3AA2h,3B00h ;
+ 3B5Fh,3BBDh,3C1Bh,3C79h,3CD7h,3D35h,3D92h,3DEFh ;/
+ 3E4Ch,3EA9h,3F05h,3F62h,3FBDh,4019h,4074h,40D0h ;\
+ 412Ah,4185h,41DFh,4239h,4292h,42EBh,4344h,439Ch ;
+ 43F4h,444Ch,44A3h,44FAh,4550h,45A6h,45FCh,4651h ;
+ 46A6h,46FAh,474Eh,47A1h,47F4h,4846h,4898h,48E9h ;
+ 493Ah,498Ah,49D9h,4A29h,4A77h,4AC5h,4B13h,4B5Fh ;
+ 4BACh,4BF7h,4C42h,4C8Dh,4CD7h,4D20h,4D68h,4DB0h ;
+ 4DF7h,4E3Eh,4E84h,4EC9h,4F0Eh,4F52h,4F95h,4FD7h ; entry
+ 5019h,505Ah,509Ah,50DAh,5118h,5156h,5194h,51D0h ; 180h..1FFh
+ 520Ch,5247h,5281h,52BAh,52F3h,532Ah,5361h,5397h ;
+ 53CCh,5401h,5434h,5467h,5499h,54CAh,54FAh,5529h ;
+ 5558h,5585h,55B2h,55DEh,5609h,5632h,565Bh,5684h ;
+ 56ABh,56D1h,56F6h,571Bh,573Eh,5761h,5782h,57A3h ;
+ 57C3h,57E2h,57FFh,581Ch,5838h,5853h,586Dh,5886h ;
+ 589Eh,58B5h,58CBh,58E0h,58F4h,5907h,5919h,592Ah ;
+ 593Ah,5949h,5958h,5965h,5971h,597Ch,5986h,598Fh ;
+ 5997h,599Eh,59A4h,59A9h,59ADh,59B0h,59B2h,59B3h ;/
+The PSX table is a bit different as the SNES table: Values up to 3569h are
+smaller as on SNES, the remaining values are bigger as on SNES, and the width
+of the PSX table entries is 4bit higher as on SNES.
+The PSX table is slightly bugged: Theoretically, each four values
+(gauss[000h+i], gauss[0FFh-i], gauss[100h+i], gauss[1FFh-i]) should sum up to
+8000h, but in practice they do sum up to 7F7Fh..7F81h (fortunately the PSX sum
+doesn't exceed the 8000h limit; meaning that the PSX interpolations won't
+overflow, which has been a hardware glitch on the SNES).
+
+Waveform Examples
+ Incoming ADPCM Data ---> Interpolated Data
+ _ _ _ _
+ | | | | | | | | . . . . Nibbles=79797979, Filter=0
+ | | | | | | | | ---> / \ / \ / \ / \ HALF-volume ZIGZAG-wave
+ | |_| |_| |_| |_ ' ' ' '
+ ___ ___
+ | | | | .'. .'. Nibbles=77997799, Filter=0
+ | | | | ---> / \ / \ FULL-volume SINE-wave
+ | |___| |___ ' '.' '.
+ _______ ___
+ | | .' '. Nibbles=77779999, Filter=0
+ | | ---> / \ SQUARE wave (with rounded edges)
+ | |_______ ' '.____
+ _____ _ __
+ | |_ _| .' ''. .' Nibbles=7777CC44, Filter=0
+ | |___| ---> / '..' CUSTOM wave-form
+ | '
+ ___ __
+ | |___| | _ \ ! / . \ ! / Nibbles=77DE9HZK, Filter=V
+ |_ ____| _| ---> - + - + - + - SOLAR STORM wave-form
+ __| |______|___ / ! \ ' / ! \
+
+
+SPU Volume and ADSR Generator
+-----------------------------
+
+1F801C08h+N*10h - Voice 0..23 Attack/Decay/Sustain/Release (ADSR) (32bit)
+ ____lower 16bit (at 1F801C08h+N*10h)___________________________________
+ 15 Attack Mode (0=Linear, 1=Exponential)
+ - Attack Direction (Fixed, always Increase) (until Level 7FFFh)
+ 14-10 Attack Shift (0..1Fh = Fast..Slow)
+ 9-8 Attack Step (0..3 = "+7,+6,+5,+4")
+ - Decay Mode (Fixed, always Exponential)
+ - Decay Direction (Fixed, always Decrease) (until Sustain Level)
+ 7-4 Decay Shift (0..0Fh = Fast..Slow)
+ - Decay Step (Fixed, always "-8")
+ 3-0 Sustain Level (0..0Fh) ;Level=(N+1)*800h
+ ____upper 16bit (at 1F801C0Ah+N*10h)___________________________________
+ 31 Sustain Mode (0=Linear, 1=Exponential)
+ 30 Sustain Direction (0=Increase, 1=Decrease) (until Key OFF flag)
+ 29 Not used? (should be zero)
+ 28-24 Sustain Shift (0..1Fh = Fast..Slow)
+ 23-22 Sustain Step (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
+ 21 Release Mode (0=Linear, 1=Exponential)
+ - Release Direction (Fixed, always Decrease) (until Level 0000h)
+ 20-16 Release Shift (0..1Fh = Fast..Slow)
+ - Release Step (Fixed, always "-8")
+The Attack phase gets started when the software sets the voice ON flag (see
+below), the hardware does then automatically go through Attack/Decay/Sustain,
+and switches from Sustain to Release when the software sets the Key OFF flag.
+
+1F801D80h - Mainvolume left
+1F801D82h - Mainvolume right
+1F801C00h+N*10h - Voice 0..23 Volume Left
+1F801C02h+N*10h - Voice 0..23 Volume Right
+Fixed Volume Mode (when Bit15=0):
+ 15 Must be zero (0=Volume Mode)
+ 0-14 Voice volume/2 (-4000h..+3FFFh = Volume -8000h..+7FFEh)
+Sweep Volume Mode (when Bit15=1):
+ 15 Must be set (1=Sweep Mode)
+ 14 Sweep Mode (0=Linear, 1=Exponential)
+ 13 Sweep Direction (0=Increase, 1=Decrease)
+ 12 Sweep Phase (0=Positive, 1=Negative)
+ 7-11 Not used? (should be zero)
+ 6-2 Sweep Shift (0..1Fh = Fast..Slow)
+ 1-0 Sweep Step (0..3 = "+7,+6,+5,+4" or "-8,-7,-6,-5") (inc/dec)
+Sweep is another Volume envelope, additionally to the ADSR volume envelope
+(unlike ADSR, sweep can be used for stereo effects, such like blending from
+left to right).
+Sweep starts at the current volume (which can be set via Bit15=0, however,
+caution - the Bit15=0 setting isn't applied until the next 44.1kHz cycle; so
+setting the initial level with Bit15=0, followed by the sweep parameter with
+Bit15=1 works only if there's a suitable delay between the two operations).
+Once when sweep is started, the current volume level increases to +7FFFh, or
+decreases to 0000h.
+Sweep Phase should be equal to the sign of the current volume (not yet tested,
+in the negative mode it does probably "increase" to -7FFFh?). The Phase bit
+seems to have no effect in Exponential Decrease mode.
+
+1F801DB0h - CD Audio Input Volume (for normal CD-DA, and compressed XA-ADPCM)
+1F801DB4h - External Audio Input Volume
+ 0-15 Volume Left (-8000h..+7FFFh)
+ 16-31 Volume Right (-8000h..+7FFFh)
+Note: The CDROM controller supports additional CD volume control (including
+ability to convert stereo CD output to mono, or to swap left/right channels).
+
+Envelope Operation depending on Shift/Step/Mode/Direction
+ AdsrCycles = 1 SHL Max(0,ShiftValue-11)
+ AdsrStep = StepValue SHL Max(0,11-ShiftValue)
+ IF exponential AND increase AND AdsrLevel>6000h THEN AdsrCycles=AdsrCycles*4
+ IF exponential AND decrease THEN AdsrStep=AdsrStep*AdsrLevel/8000h
+ Wait(AdsrCycles) ;cycles counted at 44.1kHz clock
+ AdsrLevel=AdsrLevel+AdsrStep ;saturated to 0..+7FFFh
+Exponential Increase is a fake (simply changes to a slower linear increase rate
+at higher volume levels).
+
+1F801C0Ch+N*10h - Voice 0..23 Current ADSR volume (R/W)
+ 15-0 Current ADSR Volume (0..+7FFFh) (or -8000h..+7FFFh on manual write)
+Reportedly Release can go down to -1 (FFFFh), but that isn't true; and release
+ends at 0... or does THAT depend on an END flag found in the sample-data?
+The register is read/writeable, writing allows to let the ADSR generator to
+"jump" to a specific volume level. But, ACTUALLY, the ADSR generator does
+overwrite the setting (from another internal register) whenever applying a new
+Step?!
+
+1F801DB8h - Current Main Volume Left/Right
+1F801E00h+voice*04h - Voice 0..23 Current Volume Left/Right
+ 0-15 Current Volume Left (-8000h..+7FFFh)
+ 16-31 Current Volume Right (-8000h..+7FFFh)
+These are internal registers, normally not used by software (the Volume
+settings are usually set via Ports 1F801D80h and 1F801C00h+N*10h).
+
+Note
+Negative volumes are phase inverted, otherwise same as positive.
+
+SPU Voice Flags
+---------------
+
+1F801D88h - Voice 0..23 Key ON (Start Attack/Decay/Sustain) (KON) (W)
+ 0-23 Voice 0..23 On (0=No change, 1=Start Attack/Decay/Sustain)
+ 24-31 Not used
+Starts the ADSR Envelope, and automatically initializes ADSR Volume to zero,
+and copies Voice Start Address to Voice Repeat Address.
+
+1F801D8Ch - Voice 0..23 Key OFF (Start Release) (KOFF) (W)
+ 0-23 Voice 0..23 Off (0=No change, 1=Start Release)
+ 24-31 Not used
+For a full ADSR pattern, OFF would be usually issued in the Sustain period,
+however, it can be issued at any time (eg. to abort Attack, skip the Decay and
+Sustain periods, and switch immediately to Release).
+
+1F801D9Ch - Voice 0..23 ON/OFF (status) (ENDX) (R)
+ 0-23 Voice 0..23 Status (0=Newly Keyed On, 1=Reached LOOP-END)
+ 24-31 Not used
+The bits get CLEARED when setting the corresponding KEY ON bits.
+The bits get SET when reaching an LOOP-END flag in ADPCM header.bit0.
+
+R/W
+Key On and Key Off should be treated as write-only (although, reading returns
+the most recently 32bit value, this doesn't doesn't provide any status
+information about whether sound is on or off).
+The on/off (status) (ENDX) register should be treated read-only (writing is
+possible in so far that the written value can be read-back for a short moment,
+however, thereafter the hardware is overwriting that value).
+
+SPU Noise Generator
+-------------------
+
+1F801D94h - Voice 0..23 Noise mode enable (NON)
+ 0-23 Voice 0..23 Noise (0=ADPCM, 1=Noise)
+ 24-31 Not used
+
+SPU Noise Generator
+The signed 16bit output Level is calculated as so (repeated at 44.1kHz clock):
+ Wait(1 cycle) ;at 44.1kHz clock
+ Timer=Timer-NoiseStep ;subtract Step (4..7)
+ ParityBit = NoiseLevel.Bit15 xor Bit12 xor Bit11 xor Bit10 xor 1
+ IF Timer<0 then NoiseLevel = NoiseLevel*2 + ParityBit
+ IF Timer<0 then Timer=Timer+(20000h SHR NoiseShift) ;reload timer once
+ IF Timer<0 then Timer=Timer+(20000h SHR NoiseShift) ;reload again if needed
+Note that the Noise frequency is solely controlled by the Shift/Step values in
+SPUCNT register (the ADPCM Sample Rate has absolutely no effect on noise), so
+when using noise for multiple voices, all of them are forcefully having the
+same frequency; the only workaround is to store a random ADPCM pattern in SPU
+RAM, which can be then used with any desired sample rate(s).
+
+SPU Control and Status Register
+-------------------------------
+
+1F801DAAh - SPU Control Register (SPUCNT)
+ 15 SPU Enable (0=Off, 1=On) (Don't care for CD Audio)
+ 14 Mute SPU (0=Mute, 1=Unmute) (Don't care for CD Audio)
+ 13-10 Noise Frequency Shift (0..0Fh = Low .. High Frequency)
+ 9-8 Noise Frequency Step (0..03h = Step "4,5,6,7")
+ 7 Reverb Master Enable (0=Disabled, 1=Enabled)
+ 6 IRQ9 Enable (0=Disabled/Acknowledge, 1=Enabled; only when Bit15=1)
+ 5-4 Sound RAM Transfer Mode (0=Stop, 1=ManualWrite, 2=DMAwrite, 3=DMAread)
+ 3 External Audio Reverb (0=Off, 1=On)
+ 2 CD Audio Reverb (0=Off, 1=On) (for CD-DA and XA-ADPCM)
+ 1 External Audio Enable (0=Off, 1=On)
+ 0 CD Audio Enable (0=Off, 1=On) (for CD-DA and XA-ADPCM)
+Changes to bit0-5 aren't applied immediately; after writing to SPUCNT, it'd be
+usually recommended to wait until the LSBs of SPUSTAT are updated accordingly.
+Before setting a new Transfer Mode, it'd be recommended first to set the "Stop"
+mode (and, again, wait until Stop is applied in SPUSTAT).
+
+1F801DAEh - SPU Status Register (SPUSTAT) (R)
+ 15-12 Unknown/Unused (seems to be usually zero)
+ 11 Writing to First/Second half of Capture Buffers (0=First, 1=Second)
+ 10 Data Transfer Busy Flag (0=Ready, 1=Busy)
+ 9 Data Transfer DMA Read Request (0=No, 1=Yes)
+ 8 Data Transfer DMA Write Request (0=No, 1=Yes)
+ 7 Data Transfer DMA Read/Write Request ;seems to be same as SPUCNT.Bit5
+ 6 IRQ9 Flag (0=No, 1=Interrupt Request)
+ 5-0 Current SPU Mode (same as SPUCNT.Bit5-0, but, applied a bit delayed)
+When switching SPUCNT to DMA-read mode, status bit9 and bit7 aren't set
+immediately (apparently the SPU is first internally collecting the data in the
+Fifo, before transferring it).
+Bit11 indicates if data is currently written to the first or second half of the
+four 1K-byte capture buffers (for CD Audio left/right, and voice 1/3). Note:
+Bit11 works only if Bit2 and/or Bit3 of Port 1F801DACh are set.
+The SPUSTAT register should be treated read-only (writing is possible in so far
+that the written value can be read-back for a short moment, however, thereafter
+the hardware is overwriting that value).
+
+SPU Memory Access
+-----------------
+
+1F801DA6h - Sound RAM Data Transfer Address
+ 15-0 Address in sound buffer divided by eight
+Used for manual write and DMA read/write SPU memory. Writing to this registers
+stores the written value in 1F801DA6h, and does additional store the value
+(multiplied by 8) in another internal "current address" register (that internal
+register does increment during transfers, whilst the 1F801DA6h value DOESN'T
+increment).
+
+1F801DA8h - Sound RAM Data Transfer Fifo
+ 15-0 Data (max 32 halfwords)
+Used for manual-write. Not sure if it can be also used for manual read?
+
+1F801DACh - Sound RAM Data Transfer Control (should be 0004h)
+ 15-4 Unknown/no effect? (should be zero)
+ 3-1 Sound RAM Data Transfer Type (see below) (should be 2)
+ 0 Unknown/no effect? (should be zero)
+The Transfer Type selects how data is forwarded from Fifo to SPU RAM:
+ __Transfer Type___Halfwords in Fifo________Halfwords written to SPU RAM__
+ 0,1,6,7 Fill A,B,C,D,E,F,G,H,...,X X,X,X,X,X,X,X,X,...
+ 2 Normal A,B,C,D,E,F,G,H,...,X A,B,C,D,E,F,G,H,...
+ 3 Rep2 A,B,C,D,E,F,G,H,...,X A,A,C,C,E,E,G,G,...
+ 4 Rep4 A,B,C,D,E,F,G,H,...,X A,A,A,A,E,E,E,E,...
+ 5 Rep8 A,B,C,D,E,F,G,H,...,X H,H,H,H,H,H,H,H,...
+Rep2 skips the 2nd halfword, Rep4 skips 2nd..4th, Rep8 skips 1st..7th.
+Fill uses only the LAST halfword in Fifo, that might be useful for memfill
+purposes, although, the length is probably determined by the number of writes
+to the Fifo (?) so one must still issue writes for ALL halfwords...?
+Note:
+The above rather bizarre results apply to WRITE mode. In READ mode, the
+register causes the same halfword to be read 2/4/8 times (for rep2/4/8).
+
+SPU RAM Manual Write
+- Be sure that [1F801DACh] is set to 0004h
+- Set SPUCNT to "Stop" (and wait until it is applied in SPUSTAT)
+- Set the transfer address
+- Write 1..32 halfword(s) to the Fifo
+- Set SPUCNT to "Manual Write" (and wait until it is applied in SPUSTAT)
+- Wait until Transfer Busy in SPUSTAT goes off (that, AFTER above apply-wait)
+For multi-block transfers: Repeat the above last three steps (that is rarely
+done by any games, but it is done by the BIOS intro; observe that waiting for
+SPUCNT writes being applied in SPUSTAT won't work in that case (since SPUCNT
+was already in manual write mode from previous block), so one must instead use
+some hardcoded delay of at least 300h cycles; the BIOS is using a much longer
+bizarre delay though).
+
+SPU RAM DMA-Write
+- Be sure that [1F801DACh] is set to 0004h
+- Set SPUCNT to "Stop" (and wait until it is applied in SPUSTAT)
+- Set the transfer address
+- Set SPUCNT to "DMA Write" (and wait until it is applied in SPUSTAT)
+- Start DMA4 at CPU Side (blocksize=10h, control=01000201h)
+- Wait until DMA4 finishes (at CPU side)
+
+SPU RAM Manual-Read
+As by now, there's no known method for reading SPU RAM without using DMA.
+
+SPU RAM DMA-Read (stable reading, with [1F801014h].bit24-27 = nonzero)
+- Be sure that [1F801014h] is set to 220931E1h (bit24-27 MUST be nonzero)
+- Be sure that [1F801DACh] is set to 0004h
+- Set SPUCNT to "Stop" (and wait until it is applied in SPUSTAT)
+- Set the transfer address
+- Set SPUCNT to "DMA Read" (and wait until it is applied in SPUSTAT)
+- Start DMA4 at CPU Side (blocksize=10h, control=01000200h)
+- Wait until DMA4 finishes (at CPU side)
+
+SPU RAM DMA-Read (unstable reading, with [1F801014h].bit24-27 = zero)
+Below describes some dirt effects and some trickery to get around those dirt
+effects.
+ Below problems (and workarounds) apply ONLY if [1F801014h].bit24-27 = zero.
+ Ie. below info describes what happens when [1F801014h] is mis-initialized.
+ Normally one should set [1F801014h]=220931E1h (and can ignore below info).
+With [1F801014h].bit24-27=zero, reading SPU RAM via DMA works glitchy:
+The first received halfword within each block is FFFFh. So with a DMA blocksize
+of 10h words (=20h halfwords), the following is received:
+ 1st block: FFFFh, halfwords[00h..1Eh]
+ 2nd block: FFFFh, halfwords[20h..3Eh]
+ etc.
+that'd theoretically match the SPU Fifo Size, but, because of the inserted
+FFFFh value, the last Fifo entry isn't received, ie. halfword[1Fh,3Fh] are
+lost. As a workaround, one can increase the DMA blocksize to 11h words, and
+then the following is received:
+ 1st block: FFFFh, halfwords[00h..1Eh], twice halfword[1Fh]
+ 2nd block: FFFFh, halfwords[20h..3Eh], twice halfword[3Fh]
+ etc.
+this time, all data is received, but after the transfer one must still remove
+the FFFFh values, and the duplicated halfwords by software. Aside from the
+<inserted> FFFFh values there are occassionaly some unstable halfwords ORed by
+FFFFh (or ORed by other garbage values), this can be fixed by using "rep2"
+mode, which does then receive:
+ 1st block: FFFFh, halfwords[00h,00h,..0Eh,0Eh], triple halfword[0Fh]
+ 2nd block: FFFFh, halfwords[10h,10h,..1Eh,1Eh], triple halfword[1Fh]
+ etc.
+again, remove the first halfword (FFFFh) and the last halfword, and, take the
+duplicated halfwords ANDed together. Unstable values occur only every 32
+halfwords or so (probably when the SPU is simultaneously reading ADPCM data),
+but do never occur on two continous halfwords, so, even if one halfword was
+ORed by garbage, the other halfword is always correct, and the result of the
+ANDed halfwords is 100% stable.
+Note: The unstable reading does NOT occur always, when resetting the PSX a
+couple of times it does occassionally boot-up with totally stable reading,
+since there is no known way to activate the stable "mode" via I/O ports, the
+stable/unstable behaviour does eventually depend on internal clock
+dividers/multipliers, and whether they are starting in sync with the CPU or
+not.
+Caution: The "rep2" trick cannot be used in combination with reverb (reverb
+seems to be using the Port 1F801DACh Sound RAM Data Transfer Control, too).
+
+SPU Interrupt
+-------------
+
+1F801DA4h - Sound RAM IRQ Address (IRQ9)
+ 15-0 Address in sound buffer divided by eight
+See also: SPUCNT (IRQ enable/disable/acknowledge) and SPUSTAT (IRQ flag).
+
+Voice Interrupt
+Triggers an IRQ when a voice reads ADPCM data from the IRQ address.
+Mind that ADPCM cannot be stopped (uh, except, probably they CAN be stopped, by
+setting the sample rate to zero?), all voices are permanently reading data from
+SPU RAM - even in Noise mode, even if the Voice Volume is zero, and even if the
+ADSR pattern has finished the Release period - so even inaudible voices can
+trigger IRQs. To prevent unwanted IRQs, best set all unused voices to an
+endless looped dummy ADPCM block.
+For stable IRQs, the IRQ address should be aligned to the 16-byte ADPCM blocks.
+If if the IRQ address is in the middle of a 16-byte ADPCM block, then the IRQ
+doesn't seem to trigger always (unknown why, but it seems to occassionally miss
+IRQs, even if the block gets repeated several times).
+
+Capture Interrupt
+Setting the IRQ address to 0000h..01FFh (aka byte address 00000h..00FFFh) will
+trigger IRQs on writes to the four capture buffers. Each of the four buffers
+contains 400h bytes (=200h samples), so the IRQ rate will be around 86.13Hz
+(44100Hz/200h).
+CD-Audio capture is always active (even CD-Audio output is disabld in SPUCNT,
+and even if the drive door is open). Voice capture is (probably) also always
+active (even if the corresponding voice is off).
+Capture IRQs do NOT occur if 1F801DACh.bit3-2 are both zero.
+
+Reverb Interrupt
+Reverb is also triggering interrupts if the IRQ address is located in the
+reverb buffer area. Unknown <which> of the various reverb read(s) and/or reverb
+write(s) are triggering interrupts.
+
+Data Transfers
+Data Transfers (usually via DMA4) to/from SPU-RAM do also trap SPU interrupts.
+
+Note
+IRQ Address is used by Metal Gear Solid, Legend of Mana, Tokimeki Memorial 2,
+Crash Team Racing, The Misadventures of Tron Bonne, and (somewhat?) by Need For
+Speed 3.
+
+SPU Reverb Registers
+--------------------
+
+Reverb Volume and Address Registers (R/W)
+ Port Reg Name Type Expl.
+ 1F801D84h spu vLOUT volume Reverb Output Volume Left
+ 1F801D86h spu vROUT volume Reverb Output Volume Right
+ 1F801DA2h spu mBASE base Reverb Work Area Start Address in Sound RAM
+ 1F801DC0h rev00 dAPF1 disp Reverb APF Offset 1
+ 1F801DC2h rev01 dAPF2 disp Reverb APF Offset 2
+ 1F801DC4h rev02 vIIR volume Reverb Reflection Volume 1
+ 1F801DC6h rev03 vCOMB1 volume Reverb Comb Volume 1
+ 1F801DC8h rev04 vCOMB2 volume Reverb Comb Volume 2
+ 1F801DCAh rev05 vCOMB3 volume Reverb Comb Volume 3
+ 1F801DCCh rev06 vCOMB4 volume Reverb Comb Volume 4
+ 1F801DCEh rev07 vWALL volume Reverb Reflection Volume 2
+ 1F801DD0h rev08 vAPF1 volume Reverb APF Volume 1
+ 1F801DD2h rev09 vAPF2 volume Reverb APF Volume 2
+ 1F801DD4h rev0A mLSAME src/dst Reverb Same Side Reflection Address 1 Left
+ 1F801DD6h rev0B mRSAME src/dst Reverb Same Side Reflection Address 1 Right
+ 1F801DD8h rev0C mLCOMB1 src Reverb Comb Address 1 Left
+ 1F801DDAh rev0D mRCOMB1 src Reverb Comb Address 1 Right
+ 1F801DDCh rev0E mLCOMB2 src Reverb Comb Address 2 Left
+ 1F801DDEh rev0F mRCOMB2 src Reverb Comb Address 2 Right
+ 1F801DE0h rev10 dLSAME src Reverb Same Side Reflection Address 2 Left
+ 1F801DE2h rev11 dRSAME src Reverb Same Side Reflection Address 2 Right
+ 1F801DE4h rev12 mLDIFF src/dst Reverb Different Side Reflect Address 1 Left
+ 1F801DE6h rev13 mRDIFF src/dst Reverb Different Side Reflect Address 1 Right
+ 1F801DE8h rev14 mLCOMB3 src Reverb Comb Address 3 Left
+ 1F801DEAh rev15 mRCOMB3 src Reverb Comb Address 3 Right
+ 1F801DECh rev16 mLCOMB4 src Reverb Comb Address 4 Left
+ 1F801DEEh rev17 mRCOMB4 src Reverb Comb Address 4 Right
+ 1F801DF0h rev18 dLDIFF src Reverb Different Side Reflect Address 2 Left
+ 1F801DF2h rev19 dRDIFF src Reverb Different Side Reflect Address 2 Right
+ 1F801DF4h rev1A mLAPF1 src/dst Reverb APF Address 1 Left
+ 1F801DF6h rev1B mRAPF1 src/dst Reverb APF Address 1 Right
+ 1F801DF8h rev1C mLAPF2 src/dst Reverb APF Address 2 Left
+ 1F801DFAh rev1D mRAPF2 src/dst Reverb APF Address 2 Right
+ 1F801DFCh rev1E vLIN volume Reverb Input Volume Left
+ 1F801DFEh rev1F vRIN volume Reverb Input Volume Right
+All volume registers are signed 16bit (range -8000h..+7FFFh).
+All src/dst/disp/base registers are addresses in SPU memory (divided by 8),
+src/dst are relative to the current buffer address, the disp registers are
+relative to src registers, the base register defines the start address of the
+reverb buffer (the end address is fixed, at 7FFFEh). Writing a value to mBASE
+does additionally set the current buffer address to that value.
+
+1F801D98h - Voice 0..23 Reverb mode aka Echo On (EON) (R/W)
+ 0-23 Voice 0..23 Destination (0=To Mixer, 1=To Mixer and to Reverb)
+ 24-31 Not used
+Sets reverb for the channel. As soon as the sample ends, the reverb for that
+channel is turned off... that's fine, but WHEN does it end?
+In Reverb mode, the voice seems to output BOTH normal (immediately) AND via
+Reverb (delayed).
+
+Reverb Bits in SPUCNT Register (R/W)
+The SPUCNT register contains a Reverb Master Enable flag, and Reverb Enable
+flags for External Audio input and CD Audio input.
+When the Reverb Master Enable flag is cleared, the SPU stops to write any data
+to the Reverb buffer (that is useful when zero-filling the reverb buffer;
+ensuring that already-zero values aren't overwritten by still-nonzero values).
+However, the Reverb Master Enable flag does not disable output from Reverb
+buffer to the speakers (that might be useful to output uncompressed 22050Hz
+samples) (otherwise, to disable the buffer output, set the Reverb Output volume
+to zero and/or zerofill the reverb buffer).
+
+SPU Reverb Formula
+------------------
+
+Reverb Formula
+ ___Input from Mixer (Input volume multiplied with incoming data)_____________
+ Lin = vLIN * LeftInput ;from any channels that have Reverb enabled
+ Rin = vRIN * RightInput ;from any channels that have Reverb enabled
+ ____Same Side Reflection (left-to-left and right-to-right)___________________
+ [mLSAME] = (Lin + [dLSAME]*vWALL - [mLSAME-2])*vIIR + [mLSAME-2] ;L-to-L
+ [mRSAME] = (Rin + [dRSAME]*vWALL - [mRSAME-2])*vIIR + [mRSAME-2] ;R-to-R
+ ___Different Side Reflection (left-to-right and right-to-left)_______________
+ [mLDIFF] = (Lin + [dRDIFF]*vWALL - [mLDIFF-2])*vIIR + [mLDIFF-2] ;R-to-L
+ [mRDIFF] = (Rin + [dLDIFF]*vWALL - [mRDIFF-2])*vIIR + [mRDIFF-2] ;L-to-R
+ ___Early Echo (Comb Filter, with input from buffer)__________________________
+ Lout=vCOMB1*[mLCOMB1]+vCOMB2*[mLCOMB2]+vCOMB3*[mLCOMB3]+vCOMB4*[mLCOMB4]
+ Rout=vCOMB1*[mRCOMB1]+vCOMB2*[mRCOMB2]+vCOMB3*[mRCOMB3]+vCOMB4*[mRCOMB4]
+ ___Late Reverb APF1 (All Pass Filter 1, with input from COMB)________________
+ Lout=Lout-vAPF1*[mLAPF1-dAPF1], [mLAPF1]=Lout, Lout=Lout*vAPF1+[mLAPF1-dAPF1]
+ Rout=Rout-vAPF1*[mRAPF1-dAPF1], [mRAPF1]=Rout, Rout=Rout*vAPF1+[mRAPF1-dAPF1]
+ ___Late Reverb APF2 (All Pass Filter 2, with input from APF1)________________
+ Lout=Lout-vAPF2*[mLAPF2-dAPF2], [mLAPF2]=Lout, Lout=Lout*vAPF2+[mLAPF2-dAPF2]
+ Rout=Rout-vAPF2*[mRAPF2-dAPF2], [mRAPF2]=Rout, Rout=Rout*vAPF2+[mRAPF2-dAPF2]
+ ___Output to Mixer (Output volume multiplied with input from APF2)___________
+ LeftOutput = Lout*vLOUT
+ RightOutput = Rout*vROUT
+ ___Finally, before repeating the above steps_________________________________
+ BufferAddress = MAX(mBASE, (BufferAddress+2) AND 7FFFEh)
+ Wait one 22050Hz cycle, then repeat the above stuff
+
+Notes
+The values written to memory are saturated to -8000h..+7FFFh.
+The multiplication results are divided by +8000h, to fit them to 16bit range.
+All memory addresses are relative to the current BufferAddress, and wrapped
+within mBASE..7FFFEh when exceeding that region.
+All data in the Reverb buffer consists of signed 16bit samples. The Left and
+Right Reverb Buffer addresses should be choosen so that one half of the buffer
+contains Left samples, and the other half Right samples (ie. the data is
+L,L,L,L,... R,R,R,R,...; it is NOT interlaced like L,R,L,R,...), during
+operation, when the buffer address increases, the Left half will overwrite the
+older samples of the Right half, and vice-versa.
+The reverb hardware spends one 44100h cycle on left calculations, and the next
+44100h cycle on right calculations (unlike as shown in the above formula, where
+left/right are shown simultaneously at 22050Hz).
+
+Reverb Disable
+SPUCNT.bit7 disables writes to reverb buffer, but reads from reverb buffer do
+still occur. If vAPF2 is zero then it does simply read "Lout=[mLAPF2-dAPF2]"
+and "Rout=[mRAPF2-dAPF2]". If vAPF2 is nonzero then it does additionally use
+data from APF1, if vAPF1 and vAPF2 are both nonzero then it's also using data
+from COMB. However, the SAME/DIFF stages aren't used when reverb is disabled.
+
+Bug
+vIIR works only in range -7FFFh..+7FFFh. When set to -8000h, the multiplication
+by -8000h is still done correctly, but, the final result (the value written to
+memory) gets negated (this is a pretty strange feature, it is NOT a simple
+overflow bug, it does affect the "+[mLSAME-2]" addition; although that part
+normally shouldn't be affected by the "*vIIR" multiplication). Similar effects
+might (?) occur on some other volume registers when they are set to -8000h.
+
+Speed of Sound
+The speed of sound is circa 340 meters per second (in dry air, at room
+temperature). For example, a voice that travels to a wall at 17 meters
+distance, and back to its origin, should have a delay of 0.1 seconds.
+
+SPU Reverb Examples
+-------------------
+
+Reverb Examples
+Below are some Reverb examples, showing the required memory size (ie. set Port
+1F801DA2h to "(80000h-size)/8"), and the Reverb register settings for Port
+1F801DC0h..1F801DFFh, ie. arranged like so:
+ dAPF1 dAPF2 vIIR vCOMB1 vCOMB2 vCOMB3 vCOMB4 vWALL ;1F801DC0h..CEh
+ vAPF1 vAPF2 mLSAME mRSAME mLCOMB1 mRCOMB1 mLCOMB2 mRCOMB2 ;1F801DD0h..DEh
+ dLSAME dRSAME mLDIFF mRDIFF mLCOMB3 mRCOMB3 mLCOMB4 mRCOMB4 ;1F801DE0h..EEh
+ dLDIFF dRDIFF mLAPF1 mRAPF1 mLAPF2 mRAPF2 vLIN vRIN ;1F801DF0h..FEh
+Also, don't forget to initialize Port 1F801D84h, 1F801D86h, 1F801D98h, and
+SPUCNT, and to zerofill the Reverb Buffer (so that no garbage values are output
+when activating reverb). For whatever reason, one MUST also initialize Port
+1F801DACh (otherwise reverb stays off).
+
+Room (size=26C0h bytes)
+ 007Dh,005Bh,6D80h,54B8h,BED0h,0000h,0000h,BA80h
+ 5800h,5300h,04D6h,0333h,03F0h,0227h,0374h,01EFh
+ 0334h,01B5h,0000h,0000h,0000h,0000h,0000h,0000h
+ 0000h,0000h,01B4h,0136h,00B8h,005Ch,8000h,8000h
+
+Studio Small (size=1F40h bytes)
+ 0033h,0025h,70F0h,4FA8h,BCE0h,4410h,C0F0h,9C00h
+ 5280h,4EC0h,03E4h,031Bh,03A4h,02AFh,0372h,0266h
+ 031Ch,025Dh,025Ch,018Eh,022Fh,0135h,01D2h,00B7h
+ 018Fh,00B5h,00B4h,0080h,004Ch,0026h,8000h,8000h
+
+Studio Medium (size=4840h bytes)
+ 00B1h,007Fh,70F0h,4FA8h,BCE0h,4510h,BEF0h,B4C0h
+ 5280h,4EC0h,0904h,076Bh,0824h,065Fh,07A2h,0616h
+ 076Ch,05EDh,05ECh,042Eh,050Fh,0305h,0462h,02B7h
+ 042Fh,0265h,0264h,01B2h,0100h,0080h,8000h,8000h
+
+Studio Large (size=6FE0h bytes)
+ 00E3h,00A9h,6F60h,4FA8h,BCE0h,4510h,BEF0h,A680h
+ 5680h,52C0h,0DFBh,0B58h,0D09h,0A3Ch,0BD9h,0973h
+ 0B59h,08DAh,08D9h,05E9h,07ECh,04B0h,06EFh,03D2h
+ 05EAh,031Dh,031Ch,0238h,0154h,00AAh,8000h,8000h
+
+Hall (size=ADE0h bytes)
+ 01A5h,0139h,6000h,5000h,4C00h,B800h,BC00h,C000h
+ 6000h,5C00h,15BAh,11BBh,14C2h,10BDh,11BCh,0DC1h
+ 11C0h,0DC3h,0DC0h,09C1h,0BC4h,07C1h,0A00h,06CDh
+ 09C2h,05C1h,05C0h,041Ah,0274h,013Ah,8000h,8000h
+
+Half Echo (size=3C00h bytes)
+ 0017h,0013h,70F0h,4FA8h,BCE0h,4510h,BEF0h,8500h
+ 5F80h,54C0h,0371h,02AFh,02E5h,01DFh,02B0h,01D7h
+ 0358h,026Ah,01D6h,011Eh,012Dh,00B1h,011Fh,0059h
+ 01A0h,00E3h,0058h,0040h,0028h,0014h,8000h,8000h
+
+Space Echo (size=F6C0h bytes)
+ 033Dh,0231h,7E00h,5000h,B400h,B000h,4C00h,B000h
+ 6000h,5400h,1ED6h,1A31h,1D14h,183Bh,1BC2h,16B2h
+ 1A32h,15EFh,15EEh,1055h,1334h,0F2Dh,11F6h,0C5Dh
+ 1056h,0AE1h,0AE0h,07A2h,0464h,0232h,8000h,8000h
+
+Chaos Echo (almost infinite) (size=18040h bytes)
+ 0001h,0001h,7FFFh,7FFFh,0000h,0000h,0000h,8100h
+ 0000h,0000h,1FFFh,0FFFh,1005h,0005h,0000h,0000h
+ 1005h,0005h,0000h,0000h,0000h,0000h,0000h,0000h
+ 0000h,0000h,1004h,1002h,0004h,0002h,8000h,8000h
+
+Delay (one-shot echo) (size=18040h bytes)
+ 0001h,0001h,7FFFh,7FFFh,0000h,0000h,0000h,0000h
+ 0000h,0000h,1FFFh,0FFFh,1005h,0005h,0000h,0000h
+ 1005h,0005h,0000h,0000h,0000h,0000h,0000h,0000h
+ 0000h,0000h,1004h,1002h,0004h,0002h,8000h,8000h
+
+Reverb off (size=10h dummy bytes)
+ 0000h,0000h,0000h,0000h,0000h,0000h,0000h,0000h
+ 0000h,0000h,0001h,0001h,0001h,0001h,0001h,0001h
+ 0000h,0000h,0001h,0001h,0001h,0001h,0001h,0001h
+ 0000h,0000h,0001h,0001h,0001h,0001h,0000h,0000h
+Note that the memory offsets should be 0001h here (not 0000h), otherwise
+zerofilling the reverb buffer seems to fail (maybe because zero memory offsets
+somehow cause the fill-value to mixed with the old value or so; that appears
+even when reverb master enable is zero). Also, when not using reverb, Port
+1F801D84h, 1F801D86h, 1F801D98h, and the SPUCNT reverb bits should be set to
+zero.
+
+SPU Unknown Registers
+---------------------
+
+1F801DA0h - Some kind of a read-only status register.. or just garbage..?
+ 0-15 Unknown?
+Usually 9D78h, occassionaly changes to 17DAh or 108Eh for a short moment.
+Other day: Usually 9CF8h, or occassionally 9CFAh.
+Another day: Usually 0000h, or occassionally 4000h.
+
+1F801DBCh - 4 bytes - Unknown? (R/W)
+ 80 21 4B DF
+Other day (dots = same as above):
+ .. 31 .. ..
+
+1F801E60h - 32 bytes - Unknown? (R/W)
+ 7E 61 A9 96 47 39 F9 1E E1 E1 80 DD E8 17 7F FB
+ FB BF 1D 6C 8F EC F3 04 06 23 89 45 C1 6D 31 82
+Other day (dots = same as above):
+ .. .. .. .. .. .. .. .. .. .. .. .. .. .. 7B ..
+ .. .. .. .. .. .. .. .. 04 .. .. .. .. .. .. 86
+
+The bytes at 1F801DBCh and 1F801E60h usually have the above values on
+cold-boot. The registers are read/write-able, although writing any values to
+them doesn't seem to have any effect on sound output. Also, the SPU doesn't
+seem to modify the registers at any time during sound output, nor reverb
+calculations, nor activated external audio input... the registers seem to be
+just some kind of general-purpose RAM.
+
+Interrupts
+----------
+
+1F801070h I_STAT - Interrupt status register (R=Status, W=Acknowledge)
+1F801074h I_MASK - Interrupt mask register (R/W)
+Status: Read I_STAT (0=No IRQ, 1=IRQ)
+Acknowledge: Write I_STAT (0=Clear Bit, 1=No change)
+Mask: Read/Write I_MASK (0=Disabled, 1=Enabled)
+ 0 IRQ0 VBLANK (PAL=50Hz, NTSC=60Hz)
+ 1 IRQ1 GPU Can be requested via GP0(1Fh) command (rarely used)
+ 2 IRQ2 CDROM
+ 3 IRQ3 DMA
+ 4 IRQ4 TMR0 Timer 0 aka Root Counter 0 (Sysclk or Dotclk)
+ 5 IRQ5 TMR1 Timer 1 aka Root Counter 1 (Sysclk or H-blank)
+ 6 IRQ6 TMR2 Timer 2 aka Root Counter 2 (Sysclk or Sysclk/8)
+ 7 IRQ7 Controller and Memory Card - Byte Received Interrupt
+ 8 IRQ8 SIO
+ 9 IRQ9 SPU
+ 10 IRQ10 Controller - Lightpen Interrupt (reportedly also PIO...?)
+ 11-15 Not used (always zero)
+ 16-31 Garbage
+
+Secondary IRQ10 Controller (Port 1F802030h)
+--> EXP2 DTL-H2000 I/O Ports
+
+Interrupt Request / Execution
+The interrupt request bits in I_STAT are edge-triggered, ie. the get set ONLY
+if the corresponding interrupt source changes from "false to true".
+If one or more interrupts are requested and enabled, ie. if "(I_STAT AND
+I_MASK)=nonzero", then cop0r13.bit10 gets set, and when cop0r12.bit10 and
+cop0r12.bit0 are set, too, then the interrupt gets executed.
+
+Interrupt Acknowledge
+To acknowledge an interrupt, write a "0" to the corresponding bit in I_STAT.
+Most interrupts (except IRQ0,4,5,6) must be additionally acknowledged at the
+I/O port that has caused them (eg. JOY_CTRL.bit4).
+Observe that the I_STAT bits are edge-triggered (they get set only on
+High-to-Low, or False-to-True edges). The correct acknowledge order is:
+ First, acknowledge I_STAT (eg. I_STAT.bit7=0)
+ Then, acknowledge corresponding I/O port (eg. JOY_CTRL.bit4=1)
+When doing it vice-versa, the hardware may miss further IRQs (eg. when first
+setting JOY_CTRL.4=1, then a new IRQ may occur in JOY_STAT.4 within a single
+clock cycle, thereafter, setting I_STAT.7=0 would successfully reset I_STAT.7,
+but, since JOY_STAT.4 is already set, there'll be no further edge, so I_STAT.7
+won't be ever set in future).
+
+COP0 Interrupt Handling
+Relevant COP0 registers are cop0r13 (CAUSE, reason flags), and cop0r12 (SR,
+control flags), and cop0r14 (EPC, return address), and, cop0cmd=10h (aka RFE
+opcode) is used to prepare the return from interrupts. For more info, see
+--> COP0 - Exception Handling
+
+PSX specific COP0 Notes
+COP0 has six hardware interrupt bits, of which, the PSX uses only cop0r13.bit10
+(the other ones, cop0r13.bit11-15 are always zero). cop0r13.bit10 is NOT a
+latch, ie. it gets automatically cleared as soon as "(I_STAT AND I_MASK)=zero",
+so there's no need to do an acknowledge at the cop0 side. COP0 additionally has
+two software interrupt bits, cop0r13.bit8-9, which do exist in the PSX, too,
+these bits are read/write-able latches which can be set/cleared manually to
+request/acknowledge exceptions by software.
+
+Halt Function (Wait for Interrupt)
+The PSX doesn't have a HALT opcode, so, even if the program is merely waiting
+for an interrupt to occur, the CPU is always running at full speed, which is
+resulting in high power consumption, and, in case of emulators, high CPU
+emulation load. To save energy, and to make emulation smoother on slower
+computers, I've added a Halt function for use in emulators:
+--> EXP2 Nocash Emulation Expansion
+
+DMA Channels
+------------
+
+DMA Register Summary
+ 1F80108xh DMA0 channel 0 MDECin (RAM to MDEC)
+ 1F80109xh DMA1 channel 1 MDECout (MDEC to RAM)
+ 1F8010Axh DMA2 channel 2 GPU (lists + image data)
+ 1F8010Bxh DMA3 channel 3 CDROM (CDROM to RAM)
+ 1F8010Cxh DMA4 channel 4 SPU
+ 1F8010Dxh DMA5 channel 5 PIO (Expansion Port)
+ 1F8010Exh DMA6 channel 6 OTC (reverse clear OT) (GPU related)
+ 1F8010F0h DPCR - DMA Control register
+ 1F8010F4h DICR - DMA Interrupt register
+These ports control DMA at the CPU-side. In most cases, you'll additionally
+need to initialize an address (and transfer direction, transfer enabled, etc.)
+at the remote-side (eg. at the GPU-side for DMA2).
+
+1F801080h+N*10h - D#_MADR - DMA base address (Channel 0..6) (R/W)
+ 0-23 Memory Address where the DMA will start reading from/writing to
+ 24-31 Not used (always zero)
+In SyncMode=0, the hardware doesn't update the MADR registers (it will contain
+the start address even during and after the transfer) (unless Chopping is
+enabled, in that case it does update MADR, same does probably also happen when
+getting interrupted by a higher priority DMA channel).
+In SyncMode=1 and SyncMode=2, the hardware does update MADR (it will contain
+the start address of the currently transferred block; at transfer end, it'll
+hold the end-address in SyncMode=1, or the 00FFFFFFh end-code in SyncMode=2)
+Note: Address bit0-1 are writeable, but any updated current/end addresses are
+word-aligned with bit0-1 forced to zero.
+
+1F801084h+N*10h - D#_BCR - DMA Block Control (Channel 0..6) (R/W)
+For SyncMode=0 (ie. for OTC and CDROM):
+ 0-15 BC Number of words (0001h..FFFFh) (or 0=10000h words)
+ 16-31 0 Not used (usually 0 for OTC, or 1 ("one block") for CDROM)
+For SyncMode=1 (ie. for MDEC, SPU, and GPU-vram-data):
+ 0-15 BS Blocksize (words) ;for GPU/SPU max 10h, for MDEC max 20h
+ 16-31 BA Amount of blocks ;ie. total length = BS*BA words
+For SyncMode=2 (ie. for GPU-command-lists):
+ 0-31 0 Not used (should be zero) (transfer ends at END-CODE in list)
+BC/BS/BA can be in range 0001h..FFFFh (or 0=10000h). For BS, take care not to
+set the blocksize larger than the buffer of the corresponding unit can hold.
+(GPU and SPU both have a 16-word buffer). A larger blocksize means faster
+transfer.
+SyncMode=1 decrements BA to zero, SyncMode=0 with chopping enabled decrements
+BC to zero (aside from that two cases, D#_BCR isn't changed during/after
+transfer).
+
+1F801088h+N*10h - D#_CHCR - DMA Channel Control (Channel 0..6) (R/W)
+ 0 Transfer Direction (0=To Main RAM, 1=From Main RAM)
+ 1 Memory Address Step (0=Forward;+4, 1=Backward;-4)
+ 2-7 Not used (always zero)
+ 8 Chopping Enable (0=Normal, 1=Chopping; run CPU during DMA gaps)
+ 9-10 SyncMode, Transfer Synchronisation/Mode (0-3):
+ 0 Start immediately and transfer all at once (used for CDROM, OTC)
+ 1 Sync blocks to DMA requests (used for MDEC, SPU, and GPU-data)
+ 2 Linked-List mode (used for GPU-command-lists)
+ 3 Reserved (not used)
+ 11-15 Not used (always zero)
+ 16-18 Chopping DMA Window Size (1 SHL N words)
+ 19 Not used (always zero)
+ 20-22 Chopping CPU Window Size (1 SHL N clks)
+ 23 Not used (always zero)
+ 24 Start/Busy (0=Stopped/Completed, 1=Start/Enable/Busy)
+ 25-27 Not used (always zero)
+ 28 Start/Trigger (0=Normal, 1=Manual Start; use for SyncMode=0)
+ 29 Unknown (R/W) Pause? (0=No, 1=Pause?) (For SyncMode=0 only?)
+ 30 Unknown (R/W)
+ 31 Not used (always zero)
+The Start/Trigger bit is automatically cleared upon BEGIN of the transfer, this
+bit needs to be set only in SyncMode=0 (setting it in other SyncModes would
+force the first block to be transferred instantly without DRQ, which isn't
+desired).
+The Start/Busy bit is automatically cleared upon COMPLETION of the transfer,
+this bit must be always set for all SyncModes when starting a transfer.
+For DMA6/OTC there are some restrictions, D6_CHCR has only three
+read/write-able bits: Bit24,28,30. All other bits are read-only: Bit1 is always
+1 (step=backward), and the other bits are always 0.
+
+1F8010F0h - DPCR - DMA Control Register (R/W)
+ 0-2 DMA0, MDECin Priority (0..7; 0=Highest, 7=Lowest)
+ 3 DMA0, MDECin Master Enable (0=Disable, 1=Enable)
+ 4-6 DMA1, MDECout Priority (0..7; 0=Highest, 7=Lowest)
+ 7 DMA1, MDECout Master Enable (0=Disable, 1=Enable)
+ 8-10 DMA2, GPU Priority (0..7; 0=Highest, 7=Lowest)
+ 11 DMA2, GPU Master Enable (0=Disable, 1=Enable)
+ 12-14 DMA3, CDROM Priority (0..7; 0=Highest, 7=Lowest)
+ 15 DMA3, CDROM Master Enable (0=Disable, 1=Enable)
+ 16-18 DMA4, SPU Priority (0..7; 0=Highest, 7=Lowest)
+ 19 DMA4, SPU Master Enable (0=Disable, 1=Enable)
+ 20-22 DMA5, PIO Priority (0..7; 0=Highest, 7=Lowest)
+ 23 DMA5, PIO Master Enable (0=Disable, 1=Enable)
+ 24-26 DMA6, OTC Priority (0..7; 0=Highest, 7=Lowest)
+ 27 DMA6, OTC Master Enable (0=Disable, 1=Enable)
+ 28-30 Unknown, Priority Offset or so? (R/W)
+ 31 Unknown, no effect? (R/W)
+Initial value on reset is 07654321h. If two or more channels have the same
+priority setting, then the priority is determined by the channel number
+(DMA0=Lowest, DMA6=Highest).
+
+1F8010F4h - DICR - DMA Interrupt Register (R/W)
+ 0-5 Unknown (read/write-able)
+ 6-14 Not used (always zero)
+ 15 Force IRQ (sets bit31) (0=None, 1=Force Bit31=1)
+ 16-22 IRQ Enable for DMA0..DMA6 (0=None, 1=Enable)
+ 23 IRQ Master Enable for DMA0..DMA6 (0=None, 1=Enable)
+ 24-30 IRQ Flags for DMA0..DMA6 (0=None, 1=IRQ) (Write 1 to reset)
+ 31 IRQ Master Flag (0=None, 1=IRQ) (Read only)
+IRQ flags in Bit(24+n) are set upon DMAn completion - but caution - they are
+set ONLY if enabled in Bit(16+n).
+Bit31 is a simple readonly flag that follows the following rules:
+ IF b15=1 OR (b23=1 AND (b16-22 AND b24-30)>0) THEN b31=1 ELSE b31=0
+Upon 0-to-1 transition of Bit31, the IRQ3 flag (in Port 1F801070h) gets set.
+Bit24-30 are acknowledged (reset to zero) when writing a "1" to that bits (and,
+additionally, IRQ3 must be acknowledged via Port 1F801070h).
+
+1F8010F8h (usually 7FFAC68Bh? or 0BFAC688h)
+ (changes to 7FE358D1h after DMA transfer)
+1F8010FCh (usually 00FFFFF7h) (...maybe OTC fill-value)
+ (stays so even after DMA transfer)
+Contains strange read-only values (but not the usual "Garbage").
+Not yet tested during transfer, might be remaining length and address?
+
+Commonly used DMA Control Register values for starting DMA transfers
+ DMA0 MDEC.IN 01000201h (always)
+ DMA1 MDEC.OUT 01000200h (always)
+ DMA2 GPU 01000200h (VramRead), 01000201h (VramWrite), 01000401h (List)
+ DMA3 CDROM 11000000h (normal), 11400100h (chopped, rarely used)
+ DMA4 SPU 01000201h (write), 01000200h (read, rarely used)
+ DMA5 PIO N/A (not used by any known games)
+ DMA6 OTC 11000002h (always)
+XXX: DMA2 values 01000201h (VramWrite), 01000401h (List) aren't 100% confirmed
+to be used by ALL existing games. All other values are always used as listed
+above.
+
+DMA Transfer Rates
+ DMA0 MDEC.IN 1 clk/word ;0110h clks per 100h words ;\plus whatever
+ DMA1 MDEC.OUT 1 clk/word ;0110h clks per 100h words ;/decompression time
+ DMA2 GPU 1 clk/word ;0110h clks per 100h words ;-plus ...
+ DMA3 CDROM/BIOS 24 clks/word ;1800h clks per 100h words ;\plus single/double
+ DMA3 CDROM/GAMES 40 clks/word ;2800h clks per 100h words ;/speed sector rate
+ DMA4 SPU 4 clks/word ;0420h clks per 100h words ;-plus ...
+ DMA5 PIO 20 clks/word ;1400h clks per 100h words ;-not actually used
+ DMA6 OTC 1 clk/word ;0110h clks per 100h words ;-plus nothing
+MDEC decompression time is still unknown (may vary on RLE and color/mono).
+GPU polygon rendering time is unknown (may be quite slow for large polys).
+GPU vram read/write time is unknown (may vary on horizontal screen resolution).
+CDROM BIOS default is 24 clks, for some reason most games change it to 40 clks.
+SPU transfer is unknown (may have some extra delays).
+XXX is SPU really only 4 clks (theoretically SPU access should be slower)?
+PIO isn't used by any games (and if used: could be configured to other rates)
+OTC is just writing to RAM without extra overload.
+CDROM/SPU/PIO timings can be configured via Memory Control registers.
+
+DRAM Hyper Page mode
+DMA is using DRAM Hyper Page mode, allowing it to access DRAM rows at 1 clock
+cycle per word (effectively around 17 clks per 16 words, due to required row
+address loading, probably plus some further minimal overload due to refresh
+cycles). This is making DMA much faster than CPU memory accesses (CPU DRAM
+access takes 1 opcode cycle plus 6 waitstates, ie. 7 cycles in total)
+
+CPU Operation during DMA
+Basically, the CPU is stopped during DMA (theoretically, the CPU could be kept
+running when accessing only cache, scratchpad and on-chip I/O ports like DMA
+registers, and during the CDROM/SPU/PIO waitstates it could even access Main
+RAM, but these situations aren't supported).
+However, the CPU operation resumes during periods when DMA gets interrupted
+(ie. after SyncMode 1 blocks, after SyncMode 2 list entries) (or in SyncMode 0
+with Chopping enabled).
+
+Timers
+------
+
+1F801100h+N*10h - Timer 0..2 Current Counter Value (R/W)
+ 0-15 Current Counter value (incrementing)
+ 16-31 Garbage
+This register is automatically incrementing. It is write-able (allowing to set
+it to any value). It gets forcefully reset to 0000h on any write to the Counter
+Mode register, and on counter overflow (either when exceeding FFFFh, or when
+exceeding the selected target value).
+
+1F801104h+N*10h - Timer 0..2 Counter Mode (R/W)
+ 0 Synchronization Enable (0=Free Run, 1=Synchronize via Bit1-2)
+ 1-2 Synchronization Mode (0-3, see lists below)
+ Synchronization Modes for Counter 0:
+ 0 = Pause counter during Hblank(s)
+ 1 = Reset counter to 0000h at Hblank(s)
+ 2 = Reset counter to 0000h at Hblank(s) and pause outside of Hblank
+ 3 = Pause until Hblank occurs once, then switch to Free Run
+ Synchronization Modes for Counter 1:
+ Same as above, but using Vblank instead of Hblank
+ Synchronization Modes for Counter 2:
+ 0 or 3 = Stop counter at current value (forever, no h/v-blank start)
+ 1 or 2 = Free Run (same as when Synchronization Disabled)
+ 3 Reset counter to 0000h (0=After Counter=FFFFh, 1=After Counter=Target)
+ 4 IRQ when Counter=Target (0=Disable, 1=Enable)
+ 5 IRQ when Counter=FFFFh (0=Disable, 1=Enable)
+ 6 IRQ Once/Repeat Mode (0=One-shot, 1=Repeatedly)
+ 7 IRQ Pulse/Toggle Mode (0=Short Bit10=0 Pulse, 1=Toggle Bit10 on/off)
+ 8-9 Clock Source (0-3, see list below)
+ Counter 0: 0 or 2 = System Clock, 1 or 3 = Dotclock
+ Counter 1: 0 or 2 = System Clock, 1 or 3 = Hblank
+ Counter 2: 0 or 1 = System Clock, 2 or 3 = System Clock/8
+ 10 Interrupt Request (0=Yes, 1=No) (Set after Writing) (W=1) (R)
+ 11 Reached Target Value (0=No, 1=Yes) (Reset after Reading) (R)
+ 12 Reached FFFFh Value (0=No, 1=Yes) (Reset after Reading) (R)
+ 13-15 Unknown (seems to be always zero)
+ 16-31 Garbage (next opcode)
+In one-shot mode, the IRQ is pulsed/toggled only once (one-shot mode doesn't
+stop the counter, it just suppresses any further IRQs until a new write to the
+Mode register occurs; if both IRQ conditions are enabled in Bit4-5, then
+one-shot mode triggers only one of those conditions; whichever occurs first).
+Normally, Pulse mode should be used (Bit10 is permanently set, except for a few
+clock cycles when an IRQ occurs). In Toggle mode, Bit10 is set after writing to
+the Mode register, and becomes inverted on each IRQ (in one-shot mode, it
+remains zero after the IRQ) (in repeat mode it inverts Bit10 on each IRQ, so
+IRQ4/5/6 are triggered only each 2nd time, ie. when Bit10 changes from 1 to 0).
+
+1F801108h+N*10h - Timer 0..2 Counter Target Value (R/W)
+ 0-15 Counter Target value
+ 16-31 Garbage
+When the Target flag is set (Bit3 of the Control register), the counter
+increments up to (including) the selected target value, and does then restart
+at 0000h.
+
+Dotclock/Hblank
+For more info on dotclock and hblank timings, see:
+--> GPU Timings
+Caution: Reading the Current Counter Value can be a little unstable (when using
+dotclk or hblank as clock source); the GPU clock isn't in sync with the CPU
+clock, so the timer may get changed during the CPU read cycle. As a workaround:
+repeat reading the timer until the received value is the same (or slightly
+bigger) than the previous value.
+
+CDROM Drive
+-----------
+
+Playstation CDROM I/O Ports
+--> CDROM Controller I/O Ports
+
+Playstation CDROM Commands
+--> CDROM Controller Command Summary
+--> CDROM - Control Commands
+--> CDROM - Seek Commands
+--> CDROM - Read Commands
+--> CDROM - Status Commands
+--> CDROM - CD Audio Commands
+--> CDROM - Test Commands
+--> CDROM - Secret Unlock Commands
+--> CDROM - Video CD Commands
+--> CDROM - Mainloop/Responses
+--> CDROM - Response Timings
+--> CDROM - Response/Data Queueing
+
+General CDROM Disk Format
+--> CDROM Disk Format
+--> CDROM Subchannels
+--> CDROM Sector Encoding
+--> CDROM Scrambling
+--> CDROM XA Subheader, File, Channel, Interleave
+--> CDROM XA Audio ADPCM Compression
+--> CDROM ISO Volume Descriptors
+--> CDROM ISO File and Directory Descriptors
+--> CDROM ISO Misc
+--> CDROM File Formats
+--> CDROM Video CDs (VCD)
+
+Playstation CDROM Protection
+--> CDROM Protection - SCEx Strings
+--> CDROM Protection - Bypassing it
+--> CDROM Protection - Modchips
+--> CDROM Protection - Chipless Modchips
+--> CDROM Protection - LibCrypt
+
+General CDROM Disk Images
+--> CDROM Disk Images CCD/IMG/SUB (CloneCD)
+--> CDROM Disk Images CDI (DiscJuggler)
+--> CDROM Disk Images CUE/BIN/CDT (Cdrwin)
+--> CDROM Disk Images MDS/MDF (Alcohol 120%)
+--> CDROM Disk Images NRG (Nero)
+--> CDROM Disk Image/Containers CDZ
+--> CDROM Disk Image/Containers ECM
+--> CDROM Subchannel Images
+--> CDROM Disk Images Other Formats
+
+Playstation CDROM Coprocessor
+--> CDROM Internal Info on PSX CDROM Controller
+
+CDROM Controller I/O Ports
+--------------------------
+
+1F801800h - Index/Status Register (Bit0-1 R/W) (Bit2-7 Read Only)
+ 0-1 Index Port 1F801801h-1F801803h index (0..3 = Index0..Index3) (R/W)
+ 2 ADPBUSY XA-ADPCM fifo empty (0=Empty) ;set when playing XA-ADPCM sound
+ 3 PRMEMPT Parameter fifo empty (1=Empty) ;triggered before writing 1st byte
+ 4 PRMWRDY Parameter fifo full (0=Full) ;triggered after writing 16 bytes
+ 5 RSLRRDY Response fifo empty (0=Empty) ;triggered after reading LAST byte
+ 6 DRQSTS Data fifo empty (0=Empty) ;triggered after reading LAST byte
+ 7 BUSYSTS Command/parameter transmission busy (1=Busy)
+Bit3,4,5 are bound to 5bit counters; ie. the bits become true at specified
+amount of reads/writes, and thereafter once on every further 32 reads/writes.
+
+1F801801h.Index0 - Command Register (W)
+ 0-7 Command Byte
+Writing to this address sends the command byte to the CDROM controller, which
+will then read-out any Parameter byte(s) which have been previously stored in
+the Parameter Fifo. It takes a while until the command/parameters are
+transferred to the controller, and until the response bytes are received; once
+when completed, interrupt INT3 is generated (or INT5 in case of invalid
+command/parameter values), and the response (or error code) can be then read
+from the Response Fifo. Some commands additionally have a second response,
+which is sent with another interrupt.
+
+1F801802h.Index0 - Parameter Fifo (W)
+ 0-7 Parameter Byte(s) to be used for next Command
+Before sending a command, write any parameter byte(s) to this address.
+
+1F801803h.Index0 - Request Register (W)
+ 0-4 0 Not used (should be zero)
+ 5 SMEN Want Command Start Interrupt on Next Command (0=No change, 1=Yes)
+ 6 BFWR ...
+ 7 BFRD Want Data (0=No/Reset Data Fifo, 1=Yes/Load Data Fifo)
+
+1F801802h.Index0..3 - Data Fifo - 8bit/16bit (R)
+After ReadS/ReadN commands have generated INT1, software must set the Want Data
+bit (1F801803h.Index0.Bit7), then wait until Data Fifo becomes not empty
+(1F801800h.Bit6), the datablock (disk sector) can be then read from this
+register.
+ 0-7 Data 8bit (one byte), or alternately,
+ 0-15 Data 16bit (LSB=First byte, MSB=Second byte)
+The PSX hardware allows to read 800h-byte or 924h-byte sectors, indexed as
+[000h..7FFh] or [000h..923h], when trying to read further bytes, then the PSX
+will repeat the byte at index [800h-8] or [924h-4] as padding value.
+Port 1F801802h can be accessed with 8bit or 16bit reads (ie. to read a
+2048-byte sector, one can use 2048 load-byte opcodes, or 1024 load halfword
+opcodes, or, more conventionally, a 512 word DMA transfer; the actual CDROM
+databus is only 8bits wide, so CPU/DMA are apparently breaking 16bit/32bit
+reads into multiple 8bit reads from 1F801802h).
+
+1F801801h.Index1 - Response Fifo (R)
+1F801801h.Index0,2,3 - Response Fifo (R) (Mirrors)
+ 0-7 Response Byte(s) received after sending a Command
+The response Fifo is a 16-byte buffer, most or all responses are less than 16
+bytes, after reading the last used byte (or before reading anything when the
+response is 0-byte long), Bit5 of the Index/Status register becomes zero to
+indicate that the last byte was received.
+When reading further bytes: The buffer is padded with 00h's to the end of the
+16-bytes, and does then restart at the first response byte (that, without
+receiving a new response, so it'll always return the same 16 bytes, until a new
+command/response has been sent/received).
+
+1F801802h.Index1 - Interrupt Enable Register (W)
+1F801803h.Index0 - Interrupt Enable Register (R)
+1F801803h.Index2 - Interrupt Enable Register (R) (Mirror)
+ 0-4 Interrupt Enable Bits (usually all set, ie. 1Fh=Enable All IRQs)
+ 5-7 Unknown/unused (write: should be zero) (read: usually all bits set)
+XXX WRITE: bit5-7 unused should be 0 // READ: bit5-7 unused
+
+1F801803h.Index1 - Interrupt Flag Register (R/W)
+1F801803h.Index3 - Interrupt Flag Register (R) (Mirror)
+ 0-2 Read: Response Received Write: 7=Acknowledge ;INT1..INT7
+ 3 Read: Unknown (usually 0) Write: 1=Acknowledge ;INT8 ;XXX CLRBFEMPT
+ 4 Read: Command Start Write: 1=Acknowledge ;INT10h;XXX CLRBFWRDY
+ 5 Read: Always 1 ;XXX "_" Write: 1=Unknown ;XXX SMADPCLR
+ 6 Read: Always 1 ;XXX "_" Write: 1=Reset Parameter Fifo ;XXX CLRPRM
+ 7 Read: Always 1 ;XXX "_" Write: 1=Unknown ;XXX CHPRST
+Writing "1" bits to bit0-4 resets the corresponding IRQ flags; normally one
+should write 07h to reset the response bits, or 1Fh to reset all IRQ bits.
+Writing values like 01h is possible (eg. that would change INT3 to INT2, but
+doing that would be total nonsense). After acknowledge, the Response Fifo is
+made empty, and if there's been a pending command, then that command gets send
+to the controller.
+The lower 3bit indicate the type of response received,
+ INT0 No response received (no interrupt request)
+ INT1 Received SECOND (or further) response to ReadS/ReadN (and Play+Report)
+ INT2 Received SECOND response (to various commands)
+ INT3 Received FIRST response (to any command)
+ INT4 DataEnd (when Play/Forward reaches end of disk) (maybe also for Read?)
+ INT5 Received error-code (in FIRST or SECOND response)
+ INT5 also occurs on SECOND GetID response, on unlicensed disks
+ INT5 also occurs when opening the drive door (even if no command
+ was sent, ie. even if no read-command or other command is active)
+ INT6 N/A
+ INT7 N/A
+The other 2bit indicate something else,
+ INT8 Unknown (never seen that bit set yet)
+ INT10h Command Start (when INT10h requested via 1F801803h.Index0.Bit5)
+The response interrupts are queued, for example, if the 1st response is INT3,
+and the second INT5, then INT3 is delivered first, and INT5 is not delivered
+until INT3 is acknowledged (ie. the response interrupts are NOT ORed together
+to produce INT7 or so). The upper bits however can be ORed with the lower bits
+(ie. Command Start INT10h and 1st Response INT3 would give INT13h).
+Caution - Unstable IRQ Flag polling
+IRQ flag changes aren't synced with the MIPS CPU clock. If more than one bit
+gets set (and the CPU is reading at the same time) then the CPU does
+occassionally see only one of the newly bits:
+ 0 ----------> 3 ;99.9% normal case INT3's
+ 0 ----------> 5 ;99% normal case INT5's
+ 0 ---> 1 ---> 3 ;0.1% glitch: occurs about once per thousands of INT3's
+ 0 ---> 4 ---> 5 ;1% glitch: occurs about once per hundreds of INT5's
+As workaround, do something like:
+ @@polling_lop:
+ irq_flags = [1F801803h] AND 07h ;<-- 1st read (may be still unstable)
+ if irq_flags = 00h then goto @@polling_lop
+ irq_flags = [1F801803h] AND 07h ;<-- 2nd read (should be stable now)
+ handle irq_flags and acknowledge them
+The problem applies only when manually polling the IRQ flags (an actual IRQ
+handler will get triggered when the flags get nonzero, and the flags will have
+stabilized once when the IRQ handler is reading them) (except, a combination of
+IRQ10h followed by IRQ3 can also have unstable LSBs within the IRQ handler).
+The problem occurs only on older consoles (like LATE-PU-8), not on newer
+consoles (like PSone).
+
+1F801802h.Index2 - Audio Volume for Left-CD-Out to Left-SPU-Input (W)
+1F801803h.Index2 - Audio Volume for Left-CD-Out to Right-SPU-Input (W)
+1F801801h.Index3 - Audio Volume for Right-CD-Out to Right-SPU-Input (W)
+1F801802h.Index3 - Audio Volume for Right-CD-Out to Left-SPU-Input (W)
+Allows to configure the CD for mono/stereo output (eg. values "80h,0,80h,0"
+produce normal stereo volume, values "40h,40h,40h,40h" produce mono output of
+equivalent volume).
+When using bigger values, the hardware does have some incomplete saturation
+support; the saturation works up to double volume (eg. overflows that occur on
+"FFh,0,FFh,0" or "80h,80h,80h,80h" are clipped to min/max levels), however, the
+saturation does NOT work properly when exceeding double volume (eg. mono with
+quad-volume "FFh,FFh,FFh,FFh").
+ 0-7 Volume Level (00h..FFh) (00h=Off, FFh=Max/Double, 80h=Default/Normal)
+After changing these registers, write 20h to 1F801803h.Index3.
+Unknown if any existing games are actually supporting mono output. Resident
+Evil 2 uses these ports to produce fade-in/fade-out effects (although, for that
+purpose, it should be much easier to use Port 1F801DB0h).
+
+1F801803h.Index3 - Audio Volume Apply Changes (by writing bit5=1)
+ 0 ADPMUTE Mute ADPCM (0=Normal, 1=Mute)
+ 1-4 - Unused (should be zero)
+ 5 CHNGATV Apply Audio Volume changes (0=No change, 1=Apply)
+ 6-7 - Unused (should be zero)
+
+1F801801h.Index1 - Sound Map Data Out (W)
+ 0-7 Data
+This register seems to be restricted to 8bit bus, unknown if/how the PSX DMA
+controller can write to it (it might support only 16bit data for CDROM).
+
+1F801801h.Index2 - Sound Map Coding Info (W)
+ 0 Mono/Stereo (0=Mono, 1=Stereo)
+ 1 Reserved (0)
+ 2 Sample Rate (0=37800Hz, 1=18900Hz)
+ 3 Reserved (0)
+ 4 Bits per Sample (0=4bit, 1=8bit)
+ 5 Reserved (0)
+ 6 Emphasis (0=Off, 1=Emphasis)
+ 7 Reserved (0)
+
+ =============================================================================
+
+Command Execution
+Command/Parameter transmission is indicated by bit7 of 1F801800h.
+When that bit gets zero, the response can be read immediately (immediately for
+MOST commands, but not ALL commands; so better wait for the IRQ).
+Alternately, you can wait for an IRQ (which seems to take place MUCH later),
+and then read the response.
+If there are any pending cdrom interrupts, these MUST be acknowledged before
+sending the command (otherwise bit7 of 1F801800h will stay set forever).
+
+Command Busy Flag - 1F801800h.Bit7
+Indicates ready-to-send-new-command,
+ 0=Ready to send a new command
+ 1=Busy sending a command/parameters
+Trying to send a new command in the Busy-phase causes malfunction (the older
+command seems to get lost, the newer command executes and returns its results
+and triggers an interrupt, but, thereafter, the controller seems to hang). So,
+always wait until the Busy-bit goes off before sending a command.
+When the Busy-flag goes off, a new command can be send immediately (even if the
+response from the previous command wasn't received yet), however, the new
+command stays in the Busy-phase until the IRQ from the previous command is
+acknowledged, at that point the actual transmission of the new command starts,
+and the Busy-flag goes off (once when the transmission completes).
+
+Misc
+Trying to do a 32bit read from 1F801800h returns the 8bit value at 1F801800h
+multiplied by 01010101h.
+
+To init the CD
+ -Flush all IRQs
+ -1F801803h.Index0=0
+ -Com_Delay=4901 (=1325h) (Port 1F801020h) (means 16bit or 32bit write?)
+ (the write seems to be 32bit, clearing the upper16bit of the register)
+ -Send two Getstat commands
+ -Send Command 0Ah (Init)
+ -Demute
+
+Seek-Busy Phase
+Warning: most or all of the info in the sentence below appear to incorrect
+(either that, or I didn't understand that rather confusing sentence).
+REPORTEDLY:
+"You should not send some commands while the CD is seeking (ie. Getstat returns
+with bit6 set). Thing is that stat only gets updated after a new command. I
+haven't tested this for other command, but for the play command (03h) you can
+just keep repeating the [which?] command and checking stat returned by that,
+for bit6 to go low (and bit7 to go high in this case). If you don't and try to
+do a getloc [GetlocP and/or GetlocL?] directly after the play command reports
+it's done [what done? meaning sending start-to-play was "done"? or meaning play
+reached end-of-disc?], the CD will stop. (I guess the CD can't get it's current
+location while it's seeking, so the logic stops the seek to get an exact fix,
+but never restarts..)"
+
+Sound Map Flowchart
+Sound Map mode allows to output XA-ADPCM from Main RAM (rather than from
+CDROM).
+ SPU: Init Master Volume Left/Right (Port 1F801D80h/1F801D82h)
+ SPU: Init CD Audio Volume Left/Right (Port 1F801DB0h/1F801DB2h)
+ SPU: Enable CD Audio (Port 1F801DAAh.Bit0=1)
+ CDROM/CMD: send Stop command (probably better to avoid conflicts)
+ CDROM/CMD: send Demute command (if muted) (but works only if disc inserted)
+ CDROM/HOST: init Codinginfo (Port 1F801801h.Index2)
+ CDROM/HOST: enable ADPCM (Port 1F801803h.Index3.Bit0=0) ;probably needed?
+ ... set dummy addr/len with DISHXFRC=1 ? <-- NOT required !
+ ... set SMEN ... and dummy BFWR? <-- BOTH bits required ?
+ ... maybe SMADPCLR (1F801803h.Index1.bit5) does clear SoundMap ADPCM buf?
+ transfer 900h bytes (same format as ADPCM sectors) (Port 1F801801h.Index1)
+ Note: Before sending a byte, one should wait for DRQs (1F801801h.Bit6=1)
+ Note: ADPCM output doesn't start until the last (900h'th) byte is transferred
+Sound Map mode may be very useful for testing XA-ADPCM directly from within an
+exe file (without needing a cdrom with ADPCM sectors). And, Sound Map supports
+both 4bit and 8bit compression (the SPU supports only 4bit).
+Caution: If ADPCM wasn't playing, and one sends one 900h-byte block, then it
+will get stored in one of three 900h-byte slots in SRAM, and one would expect
+that slot to be played when the ADPCM output starts - however, actually, the
+hardware will more or less randomly play one of the three slots; not
+necessarily the slot that was updated most recently.
+
+CDROM Controller Command Summary
+--------------------------------
+
+Command Summary
+ Command Parameters Response(s)
+ 00h - - INT5(11h,40h) ;reportedly "Sync" uh?
+ 01h Getstat - INT3(stat)
+ 02h Setloc E amm,ass,asect INT3(stat)
+ 03h Play E (track) INT3(stat), optional INT1(report bytes)
+ 04h Forward E - INT3(stat), optional INT1(report bytes)
+ 05h Backward E - INT3(stat), optional INT1(report bytes)
+ 06h ReadN E - INT3(stat), INT1(stat), datablock
+ 07h MotorOn E - INT3(stat), INT2(stat)
+ 08h Stop E - INT3(stat), INT2(stat)
+ 09h Pause E - INT3(stat), INT2(stat)
+ 0Ah Init - INT3(late-stat), INT2(stat)
+ 0Bh Mute E - INT3(stat)
+ 0Ch Demute E - INT3(stat)
+ 0Dh Setfilter E file,channel INT3(stat)
+ 0Eh Setmode mode INT3(stat)
+ 0Fh Getparam - INT3(stat,mode,null,file,channel)
+ 10h GetlocL E - INT3(amm,ass,asect,mode,file,channel,sm,ci)
+ 11h GetlocP E - INT3(track,index,mm,ss,sect,amm,ass,asect)
+ 12h SetSession E session INT3(stat), INT2(stat)
+ 13h GetTN E - INT3(stat,first,last) ;BCD
+ 14h GetTD E track (BCD) INT3(stat,mm,ss) ;BCD
+ 15h SeekL E - INT3(stat), INT2(stat) ;\use prior Setloc
+ 16h SeekP E - INT3(stat), INT2(stat) ;/to set target
+ 17h - - INT5(11h,40h) ;reportedly "SetClock" uh?
+ 18h - - INT5(11h,40h) ;reportedly "GetClock" uh?
+ 19h Test sub_function depends on sub_function (see below)
+ 1Ah GetID E - INT3(stat), INT2/5(stat,flg,typ,atip,"SCEx")
+ 1Bh ReadS E?- INT3(stat), INT1(stat), datablock
+ 1Ch Reset - INT3(stat), Delay
+ 1Dh GetQ E adr,point INT3(stat), INT2(10bytesSubQ,peak_lo) ;\not
+ 1Eh ReadTOC - INT3(late-stat), INT2(stat) ;/vC0
+ 1Fh VideoCD sub,a,b,c,d,e INT3(stat,a,b,c,d,e) ;<-- SCPH-5903 only
+ 1Fh..4Fh - - INT5(11h,40h) ;-Unused/invalid
+ 50h Secret 1 - INT5(11h,40h) ;\
+ 51h Secret 2 "Licensed by" INT5(11h,40h) ;
+ 52h Secret 3 "Sony" INT5(11h,40h) ; Secret Unlock Commands
+ 53h Secret 4 "Computer" INT5(11h,40h) ; (not in version vC0, and,
+ 54h Secret 5 "Entertainment" INT5(11h,40h) ; nonfunctional in japan)
+ 55h Secret 6 "<region>" INT5(11h,40h) ;
+ 56h Secret 7 - INT5(11h,40h) ;/
+ 57h SecretLock - INT5(11h,40h) ;-Secret Lock Command
+ 58h..5Fh Crash - Crashes the HC05 (jumps into a data area)
+ 6Fh..FFh - - INT5(11h,40h) ;-Unused/invalid
+E = Error 80h appears on some commands (02h..09h, 0Bh..0Dh, 10h..16h, 1Ah,
+1Bh?, and 1Dh) when the disk is missing, or when the drive unit is disconnected
+from the mainboard.
+
+sub_function numbers (for command 19h)
+Test commands are invoked with command number 19h, followed by a sub_function
+number as first parameter byte. The Kernel seems to be using only sub_function
+20h (to detect the CDROM Controller version).
+ sub params response ;Effect
+ 00h - INT3(stat) ;Force motor on, clockwise, even if door open
+ 01h - INT3(stat) ;Force motor on, anti-clockwise, super-fast
+ 02h - INT3(stat) ;Force motor on, anti-clockwise, super-fast
+ 03h - INT3(stat) ;Force motor off (ignored during spin-up)
+ 04h - INT3(stat) ;Start SCEx reading and reset counters
+ 05h - INT3(total,success);Stop SCEx reading and get counters
+ 06h * n INT3(old) ;\early ;Adjust balance in RAM, send CX(30+n XOR 7)
+ 07h * n INT3(old) ; PSX ;Adjust gain in RAM, send CX(38+n XOR 7)
+ 08h * n INT3(old) ;/only ;Adjust balance in RAM only
+ 06h..0Fh - INT5(11h,10h) ;N/A (11h,20h when NONZERO number of params)
+ 10h - INT3(stat) ;CX(..) ;Force motor on, anti-clockwise, super-fast
+ 11h - INT3(stat) ;CX(03) ;Move Lens Up (leave parking position)
+ 12h - INT3(stat) ;CX(02) ;Move Lens Down (enter parking position)
+ 13h - INT3(stat) ;CX(28) ;Move Lens Outwards
+ 14h - INT3(stat) ;CX(2C) ;Move Lens Inwards
+ 15h - INT3(stat) ;CX(22) ;If motor on: Move outwards,inwards,motor off
+ 16h - INT3(stat) ;CX(23) ;No effect?
+ 17h - INT3(stat) ;CX(E8) ;Force motor on, clockwise, super-fast
+ 18h - INT3(stat) ;CX(EA) ;Force motor on, anti-clockwise, super-fast
+ 19h - INT3(stat) ;CX(25) ;No effect?
+ 1Ah - INT3(stat) ;CX(21) ;No effect?
+ 1Bh..1Fh - INT5(11h,10h) ;N/A (11h,20h when NONZERO number of params)
+ 20h - INT3(yy,mm,dd,ver) ;Get cdrom BIOS date/version (yy,mm,dd,ver)
+ 21h - INT3(n) ;Get Drive Switches (bit0=POS0, bit1=DOOR)
+ 22h *** - INT3("for ...") ;Get Region ID String
+ 23h *** - INT3("CXD...") ;Get Chip ID String for Servo Amplifier
+ 24h *** - INT3("CXD...") ;Get Chip ID String for Signal Processor
+ 25h *** - INT3("CXD...") ;Get Chip ID String for Decoder/FIFO
+ 26h..2Fh - INT5(11h,10h) ;N/A (11h,20h when NONZERO number of params)
+ 30h * i,x,y INT3(stat) ;Prototype/Debug stuff ;\supported on
+ 31h * x,y INT3(stat) ;Prototype/Debug stuff ; early PSX only
+ 4xh * i INT3(x,y) ;Prototype/Debug stuff ;/
+ 30h..4Fh .. INT5(11h,10h) ;N/A always 11h,10h (no matter of params)
+ 50h a[,b[,c]] INT3(stat) ;Servo/Signal send CX(a:b:c)
+ 51h ** 39h,xx INT3(stat,hi,lo) ;Servo/Signal send CX(39xx) with response
+ 51h..5Fh - INT5(11h,10h) ;N/A
+ 60h lo,hi INT3(databyte) ;HC05 SUB-CPU read RAM and I/O ports
+ 61h..70h - INT5(11h,10h) ;N/A
+ 71h *** adr INT3(databyte) ;Decoder Read one register
+ 72h *** adr,dat INT3(stat) ;Decoder Write one register
+ 73h *** adr,len INT3(databytes..);Decoder Read multiple registers, bugged
+ 74h *** adr,len,..INT3(stat) ;Decoder Write multiple registers, bugged
+ 75h *** - INT3(lo,hi,lo,hi);Decoder Get Host Xfer Info Remain/Addr
+ 76h *** a,b,c,d INT3(stat) ;Decoder Prepare Transfer to/from SRAM
+ 77h..FFh - INT5(11h,10h) ;N/A
+ 80h..8Fh a,b ? ;seem to do something on PS2
+* sub_functions 06h..08h, 30h..31h, and 4xh are supported only in vC0 and vC1.
+** sub_function 51h is supported only in BIOS version vC2 and up.
+*** sub_functions 22h..25h, 71h..76h supported only in BIOS version vC1 and up.
+
+Unsupported GetQ,VCD,SecretUnlock (command 1Dh,1Fh,5xh)
+INT5 will be returned if the command is unsupported. That, WITHOUT removing the
+Parameters from the FIFO, so the parameters will be accidently passed to the
+NEXT command. To avoid that: clear the parameter FIFO via
+[1F801803h.Index1]=40h after receiving the INT5 error.
+
+CDROM - Control Commands
+------------------------
+
+Sync - Command 00h --> INTx(stat+1,40h) (?)
+Reportedly "command does not succeed until all other commands complete. This
+can be used for synchronization - hence the name."
+Uh, actually, returns error code 40h = Invalid Command...?
+
+Setfilter - Command 0Dh,file,channel --> INT3(stat)
+Automatic ADPCM (CD-ROM XA) filter ignores sectors except those which have the
+same channel and file numbers in their subheader. This is the mechanism used to
+select which of multiple songs in a single .XA file to play.
+Setfilter does not affect actual reading (sector reads still occur for all
+sectors).
+XXX err... that is... does not affect reading of non-ADPCM sectors (normal
+"data" sectors are kept received regardless of Setfilter).
+
+Setmode - Command 0Eh,mode --> INT3(stat)
+ 7 Speed (0=Normal speed, 1=Double speed)
+ 6 XA-ADPCM (0=Off, 1=Send XA-ADPCM sectors to SPU Audio Input)
+ 5 Sector Size (0=800h=DataOnly, 1=924h=WholeSectorExceptSyncBytes)
+ 4 Ignore Bit (0=Normal, 1=Ignore Sector Size and Setloc position)
+ 3 XA-Filter (0=Off, 1=Process only XA-ADPCM sectors that match Setfilter)
+ 2 Report (0=Off, 1=Enable Report-Interrupts for Audio Play)
+ 1 AutoPause (0=Off, 1=Auto Pause upon End of Track) ;for Audio Play
+ 0 CDDA (0=Off, 1=Allow to Read CD-DA Sectors; ignore missing EDC)
+The "Ignore Bit" does reportedly force a sector size of 2328 bytes (918h),
+however, that doesn't seem to be true. Instead, Bit4 seems to cause the
+controller to ignore the sector size in Bit5 (instead, the size is kept from
+the most recent Setmode command which didn't have Bit4 set). Also, Bit4 seems
+to cause the controller to ignore the <exact> Setloc position (instead, data is
+randomly returned from the "Setloc position minus 0..3 sectors"). And, Bit4
+causes INT1 to return status.Bit3=set (IdError). Purpose of Bit4 is unknown?
+
+Init - Command 0Ah --> INT3(stat) --> INT2(stat)
+Multiple effects at once. Sets mode=20h, activates drive motor, Standby, abort
+all commands.
+
+Reset - Command 1Ch,(...) --> INT3(stat) --> Delay(1/8 seconds)
+Resets the drive controller, reportedly, same as opening and closing the drive
+door. The command executes no matter if/how many parameters are used (tested
+with 0..7 params). INT3 indicates that the command was started, but there's no
+INT that would indicate when the command is finished, so, before sending any
+further commands, a delay of 1/8 seconds (or 400000h clock cycles) must be
+issued by software.
+Note: Executing the command produces a click sound in the drive mechanics,
+maybe it's just a rapid motor on/off, but it might something more serious, like
+ignoring the /POS0 signal...?
+
+MotorOn - Command 07h --> INT3(stat) --> INT2(stat)
+Activates the drive motor, works ONLY if the motor was off (otherwise fails
+with INT5(stat,20h); that error code would normally indicate "wrong number of
+parameters", but means "motor already on" in this case).
+Commands like Read, Seek, and Play are automatically starting the Motor when
+needed (which makes the MotorOn command rather useless, and it's rarely used by
+any games).
+Myth: Older homebrew docs are referring to MotorOn as "Standby", claiming that
+it would work similar as "Pause", that is wrong: the command does NOT pause
+anything (if the motor is on, then it does simply trigger INT5, but without
+pausing reading or playing).
+Note: The game "Nightmare Creatures 2" does actually attempt to use MotorOn to
+"pause" after reading files, but the hardware does simply ignore that attempt
+(aside from doing the INT5 thing).
+
+Stop - Command 08h --> INT3(stat) --> INT2(stat)
+Stops motor with magnetic brakes (stops within a second or so) (unlike
+power-off where it'd keep spinning for about 10 seconds), and moves the drive
+head to the begin of the first track. Official way to restart is command 0Ah,
+but almost any command will restart it.
+The first response returns the current status (this already with bit5 cleared),
+the second response returns the new status (with bit1 cleared).
+
+Pause - Command 09h --> INT3(stat) --> INT2(stat)
+Aborts Reading and Playing, the motor is kept spinning, and the drive head
+maintains the current location within reasonable error.
+The first response returns the current status (still with bit5 set if a Read
+command was active), the second response returns the new status (with bit5
+cleared).
+
+Data/ADPCM Sector Filtering/Delivery
+The PSX CDROM BIOS is first trying to send sectors to the ADPCM decoder, and,
+if that didn't work out, then it's trying to send them to the main CPU (and if
+that didn't work out either, then it's silently ignoring the sector).
+ try_deliver_as_adpcm_sector:
+ reject if CD-DA AUDIO format
+ reject if sector isn't MODE2 format
+ reject if adpcm_disabled(setmode.6)
+ reject if filter_enabled(setmode.3) AND selected file/channel doesn't match
+ reject if submode isn't audio+realtime (bit2 and bit6 must be both set)
+ deliver: send sector to xa-adpcm decoder when passing above cases
+ try_deliver_as_data_sector:
+ reject data-delivery if "try_deliver_as_adpcm_sector" did do adpcm-delivery
+ reject if filter_enabled(setmode.3) AND submode is audio+realtime (bit2+bit6)
+ 1st delivery attempt: send INT1+data, unless there's another INT pending
+ delay, and retry at later time... but this time with file/channel checking!
+ reject if filter_enabled(setmode.3) AND selected file/channel doesn't match
+ 2nd delivery attempt: send INT1+data, unless there's another INT pending
+BUG: Note that the data delivery is done in two different attempts: The first
+one regardless of file/channel, and the second one only on matching
+file/channel (if filtering is enabled).
+
+CDROM - Seek Commands
+---------------------
+
+Setloc - Command 02h,amm,ass,asect --> INT3(stat)
+Sets the seek target - but without yet starting the seek operation. The actual
+seek is invoked by certain commands: SeekL (Data) and SeekP (Audio) are doing
+plain seeks (and do Pause after completion). ReadN/ReadS are similar to SeekL
+(and do start reading data after the seek operation). Play is similar to SeekP
+(and does start playing audio after the seek operation).
+The amm,ass,asect parameters refer to the entire disk (not to the current
+track). To seek to a specific location within a specific track, use GetTD to
+get the start address of the track, and add the desired time offset to it.
+
+SeekL - Command 15h --> INT3(stat) --> INT2(stat)
+Seek to Setloc's location in data mode (using data sector header position data,
+which works/exists only on Data tracks, not on CD-DA Audio tracks).
+After the seek, the disk stays on the seeked location forever (namely: when
+seeking sector N, it does stay at around N-8..N-0 in single speed mode, or at
+around N-5..N+2 in double speed mode).
+Trying to use SeekL on Audio CDs passes okay on the first response, but (after
+two seconds or so) the second response will return an error (stat+4,04h), and
+stop the drive motor... that error doesn't appear ALWAYS though... works in
+some situations... such like when previously reading data sectors or so...?
+
+SeekP - Command 16h --> INT3(stat) --> INT2(stat)
+Seek to Setloc's location in audio mode (using the Subchannel Q position data,
+which works on both Audio on Data disks).
+After the seek, the disk stays on the seeked location forever (namely: when
+seeking sector N, it does stay at around N-9..N-1 in single speed mode, or at
+around N-2..N in double speed mode).
+Note: Some older docs claim that SeekP would recurse only "MM:SS" of the
+"MM:SS:FF" position from Setloc - that is wrong, it does seek to MM:SS:FF
+(verified on a PSone).
+After the seek, status is stat.bit7=0 (ie. audio playback off), until sending a
+new Play command (without parameters) to start playback at the seeked location.
+
+SetSession - Command 12h,session --> INT3(stat) --> INT2(stat)
+Seeks to session (ie. moves the drive head to the session, with stat bit6 set
+during the seek phase).
+When issued during active-play, the command returns error code 80h.
+When issued during play-spin-up, play is aborted.
+ ___Errors___
+ session = 00h causes error code 10h. ;INT5(03h,10h), no 2nd/3rd response
+ ___On a non-multisession-disk___
+ session = 01h passes okay. ;INT3(stat), and once INT2(stat)
+ session = 02h or higher cause seek error ;INT3(stat), and twice INT5(06h,40h)
+ ___On a multisession-disk with N sessions___
+ session = 01h..N+1 passes okay ;where N+1 moves to the END of LAST session
+ session = N+2 or higher cause seek error ;2nd response = INT5(06h,20h)
+after seek error --> disk stops spinning at 2nd response, then restarts
+spinning for 1 second or so, then stops spinning forever... and following
+gettn/gettd/getid/getlocl/getlocp fail with error 80h...
+The command does automatically read the TOC of the new session.
+There seems to be no way to determine the current sessions number (via Getparam
+or so), and more important, no way to determine if the disk is a multi-session
+disk or not... except by trial... which would stop the drive motor on seek
+errors on single-session disks...?
+For setloc, one must probably specifiy minutes within the 1st track of the new
+session (the 1st track of 1st session usually/always starts at 00:02:00, but
+for other sessions one would need to use GetTD)...?
+
+CDROM - Read Commands
+---------------------
+
+ReadN - Command 06h --> INT3(stat) --> INT1(stat) --> datablock
+Read with retry. The command responds once with "stat,INT3", and then it's
+repeatedly sending "stat,INT1 --> datablock", that is continued even after a
+successful read has occured; use the Pause command to terminate the repeated
+INT1 responses.
+Unknown which responses are sent in case of read errors?
+====
+ReadN and ReadS cause errors if you're trying to read an unlicensed CD or CD-R
+without a mod chip. Sectors on Audio CDs can be read only when CDDA is enabled
+via Setmode (otherwise error code 40h is returned).
+====
+Actually, Read seems to work on unlicensed CD-R's, but the returned data is the
+whole sector or so (the 2048 data bytes preceeded by a 12byte header, and
+probably/maybe followed by error-correction info; in fact the total received
+data in the Data Fifo is 4096 bytes; the last some bytes probably being
+garbage) (however error correction is NOT performed by hardware, so the 2048
+data bytes may be trashy) (however, if the error correction info IS received,
+then error correction could be performed by software) (also Setloc doesn't seem
+to work accurately on unlicensed CD-R's).
+====
+ ;Read occasionally returns 11h,40h ..? when TOC isn't loaded?
+After receiving INT1, the Kernel does,
+ [1F801800h]=00h
+ 00h=[1F801800h]
+ [1F801803h]=00h
+ 00h=[1F801803h]
+ [1F801800h]=00h
+ [1F801803h]=80h
+and then,
+ [1F801018h]=00020943h ;cdrom_delay
+ [1F801020h]=0000132Ch ;com_delay
+then,
+ x=[1F8010F4h] AND 00FFFFFFh ;result is 00840000h
+ [1F8010F4h] = x OR 00880000h
+ [1F8010F0h] = [1F8010F0h] OR 00008000h
+ [1F8010B0h] = A0010000h ;addr
+ [1F8010B4h] = 00010200h ;LSBs=num words, MSBs=ignored/bullshit
+ [1F8010B4h] = 11000000h ;DMA control
+thereafter,
+ [1F801800h]=01h
+ [1F801803h]=40h ;reset parameter fifo
+ [0]=00000000h
+ [0]=00000001h
+ [0]=00000002h
+ [0]=00000003h
+ [1F801800h]=00h
+ [1F801801h]=09h ;command9 (pause)
+
+ReadS - Command 1Bh --> INT3(stat) --> INT1(stat) --> datablock
+Read without automatic retry. Not sure what that means... does WHAT on errors?
+Maybe intended for continous streaming video output (to skip bad frames, rather
+than to interrupt the stream by performing read-retrys).
+
+ReadN/ReadS
+Both ReadN/ReadS are reading data sequentially, starting at the sector
+specified with Setloc, and then automatically reading the following sectors.
+
+CDROM Incoming Data / Buffer Overrun Timings
+The Read commands are continously receiving 75 sectors per second (or 150
+sectors at double speed), and, basically, the software must be fast enough to
+process that amount of incoming data. However, the PSX hardware includes a
+buffer that can hold up to a handful (exact number is unknown?) of sectors, so,
+occasional delays of more than 1/75 seconds between processing two sectors
+aren't causing lost sectors, unless the delay(s) are summing up too much. The
+relevant steps for receiving data are:
+ Wait for Interrupt Request (INT1) ;indicates that data is available
+ Send Data Request (1F801803h.Index0.Bit7=1);accept data
+ Acknowledge INT1 ;
+ Copy Data to Main RAM (via I/O or DMA) ;read data
+The Data Request accepts the data for the currently pending interrupt, it
+should be usually issued between receiving/acknowledging INT1 (however, it can
+be also issued shortly after the acknowledge; even if there are further sectors
+in the buffer, there seems to be a small delay between the acknowledge and the
+next interrupt, and Data Requests during that period are still treated to
+belong to the old interrupt).
+If a buffer overrun has occured <before> issuing the Data Request, then wrong
+data will be received, ie. some sectors will be skipped (the hardware doesn't
+seem to support a buffer-overrun error flag? Anyways, see GetlocL description
+for a possible way to detect buffer-overruns).
+If a buffer overrun occurs <after> issuing the Data Request, then the requested
+data can be still read via I/O or DMA intactly, ie. the requested data is
+"locked", and the overrun will affect only the following sectors.
+
+ReadTOC - Command 1Eh --> INT3(stat) --> INT2(stat)
+ Caution: Supported only in BIOS version vC1 and up. Not supported in vC0.
+Reread the Table of Contents of current session without reset. The command is
+rather slow, the second response appears after about 1 second delay. The
+command itself returns only status information (to get the actual TOC info, use
+GetTD and GetTN commands).
+Note: The TOC contains information about the tracks on the disk (not file names
+or so, that kind of information is obtained via Read commands). The TOC is read
+automatically on power-up, when opening/closing the drive door, and when
+changing sessions (so, normally, it isn't required to use this command).
+
+Setloc, Read, Pause
+A normal CDROM access (such like reading a file) consists of three commands:
+ Setloc, Read, Pause
+Normally one shouldn't mess up the ordering of those commands, but if one does,
+following rules do apply:
+Setloc is memorizing the wanted target, and marks it as unprocessed, and has no
+other effect (it doesn't start reading or seeking, and doesn't interrupt or
+redirect any active reads).
+If Read is issued with an unprocessed Setloc, then the drive is automatically
+seeking the Setloc location (and marks Setloc as processed).
+If Read is issued without an unprocessed Setloc, the following happens: If
+reading is already in progress then it just continues reading. If Reading was
+Paused, then reading resumes at the most recently received sector (ie.
+returning that sector once another time).
+
+CDROM - Status Commands
+-----------------------
+
+Status code (stat)
+The 8bit status code is returned by Getstat command (and many other commands),
+the meaning of the separate stat bits is:
+ 7 Play Playing CD-DA ;\only ONE of these bits can be set
+ 6 Seek Seeking ; at a time (ie. Read/Play won't get
+ 5 Read Reading data sectors ;/set until after Seek completion)
+ 4 ShellOpen Once shell open (0=Closed, 1=Is/was Open)
+ 3 IdError (0=Okay, 1=GetID denied) (also set when Setmode.Bit4=1)
+ 2 SeekError (0=Okay, 1=Seek error) (followed by Error Byte)
+ 1 Spindle Motor (0=Motor off, or in spin-up phase, 1=Motor on)
+ 0 Error Invalid Command/parameters (followed by Error Byte)
+If the shell is closed, then bit4 is automatically reset to zero after reading
+stat with the Getstat command (most or all other commands do not reset that bit
+after reading). If stat bit0 or bit2 is set, then the normal respons(es) and
+interrupt(s) are not send, and, instead, INT5 occurs, and an error-byte is send
+as second response byte, with the following values:
+ ___These values appear in the FIRST response; with stat.bit0 set___
+ 10h - Invalid Sub_function (for command 19h), or invalid parameter value
+ 20h - Wrong number of parameters
+ 40h - Invalid command
+ 80h - Cannot respond yet (eg. required info was not yet read from disk yet)
+ (namely, TOC not-yet-read or so)
+ (also appears if no disk inserted at all)
+ ___These values appear in the SECOND response; with stat.bit2 set___
+ 04h - Seek failed (when trying to use SeekL on Audio CDs)
+ ___These values appear even if no command was sent; with stat.bit2 set___
+ 08h - Drive door became opened
+80h appears on some commands (02h..09h, 0Bh..0Dh, 10h..16h, 1Ah, 1Bh?, and 1Dh)
+when the disk is missing, or when the drive unit is disconnected from the
+mainboard.
+
+Stat Seek/Play/Read bits
+There's is only max ONE of the three Seek/Play/Read bits set at a time, ie.
+during Seek, ONLY the seek bit is set (and Read or Play doesn't get until seek
+completion), that is important for Gran Turismo 1, which checks for seek
+completion by waiting for READ getting set (rather than waiting for SEEK
+getting cleared).
+
+Getstat - Command 01h --> INT3(stat)
+Returns stat (like many other commands), and additionally does reset the shell
+open flag (for the following commands; unless the shell is still opened). This
+is different as for most or all other commands (which may return stat, but
+which do not reset the shell open flag).
+In other docs, the command is eventually referred to as "Nop", believing that
+it does nothing than returning stat (ignoring the fact that it's having the
+special shell open reset feature).
+
+Getparam - Command 0Fh --> INT3(stat,mode,null,file,channel)
+Returns stat (see Getstat above), mode (see Setmode), a null byte (always 00h),
+and file/channel filter values (see Setfilter).
+
+GetlocL - Command 10h --> INT3(amm,ass,asect,mode,file,channel,sm,ci)
+Retrieves 4-byte sector header, plus 4-byte subheader of the current sector.
+GetlocL can be send during active Read commands (but, mind that the
+GetlocL-INT3-response can't be received until any pending Read-INT1's are
+acknowledged).
+The PSX hardware can buffer a handful of sectors, the INT1 handler receives the
+<oldest> buffered sector, the GetlocL command returns the header and subheader
+of the <newest> buffered sector. Note: If the returned <newest> sector number
+is much bigger than the expected <oldest> sector number, then it's likely that
+a buffer overrun has occured.
+GetlocL fails (with error code 80h) when playing Audio CDs (or Audio Tracks on
+Data CDs). These errors occur because Audio sectors don't have any
+header/subheader (instead, equivalent data is stored in Subchannel Q, which can
+be read with GetlocP).
+GetlocL also fails (with error code 80h) when the drive is in Seek phase (such
+like shortly after a new ReadN/ReadS command). In that case one can retry
+issuing GetlocL (until it passes okay, ie. until the seek has completed).
+During Seek, the drive seems to decode only Subchannel position data (but no
+header/subheader data), accordingly GetlocL won't work during seek (however,
+GetlocP does work during Seek).
+
+GetlocP - Command 11h - INT3(track,index,mm,ss,sect,amm,ass,asect)
+Retrieves 8 bytes of position information from Subchannel Q with ADR=1. Mainly
+intended for displaying the current audio position during Play. All results are
+in BCD.
+ track: track number (AAh=Lead-out area) (FFh=unknown, toc, none?)
+ index: index number (Usually 01h)
+ mm: minute number within track (00h and up)
+ ss: second number within track (00h to 59h)
+ sect: sector number within track (00h to 74h)
+ amm: minute number on entire disk (00h and up)
+ ass: second number on entire disk (00h to 59h)
+ asect: sector number on entire disk (00h to 74h)
+Note: GetlocP is also used for reading the LibCrypt protection data:
+--> CDROM Protection - LibCrypt
+
+GetTN - Command 13h --> INT3(stat,first,last) ;BCD
+Get first track number, and last track number in the TOC of the current
+Session. The number of tracks in the current session can be calculated as
+(last-first+1). The first track number is usually 01h in the first (or only)
+session, and "last track of previous session plus 1" in further sessions.
+
+GetTD - Command 14h,track --> INT3(stat,mm,ss) ;BCD
+For a disk with NN tracks, parameter values 01h..NNh return the start of the
+specified track, parameter value 00h returns the end of the last track, and
+parameter values bigger than NNh return error code 10h.
+The GetTD values are relative to Index=1 and are rounded down to second
+boundaries (eg. if track=N Index=0 starts at 12:34:56, and Track=N Index=1
+starts at 12:36:56, then GetTD(N) will return 12:36, ie. the sector number is
+truncated, and the Index=0 region is skipped).
+
+GetQ - Command 1Dh,adr,point --> INT3(stat) --> INT2(10bytesSubQ,peak_lo)
+ Caution: Supported only in BIOS version vC1 and up. Not supported in vC0.
+ Caution: When unsupported, Parameter Fifo isn't cleared after the command.
+Allows to read 10 bytes from Subchannel Q in Lead-In (see CDROM Subchannels
+chapter for details). Unlike GetTD, this command allows to receive the exact
+MM:SS:FF address of the point'ed Track (GetTD reads a memorized MM:SS value
+from RAM, whilst GetQ reads the full MM:SS:FF from the disk, which is slower
+than GetTD, due to the disk-access).
+With ADR=1, point can be a any point number for ADR=1 in Lead-in (eg.
+01h..99h=Track N, A2h=Lead-Out). The returned 10 bytes are raw SubQ data
+(starting with the ADR/Control value; of which the lower 4bits are always
+ADR=1).
+The 11th returned byte is the Peak LSB (similar as in Play+Report, but in this
+case only the LSB is transferred, which is apparently a bug in CDROM BIOS, the
+programmer probably wanted to send 10 bytes without peak, or 12 bytes with full
+peak; although peak wouldn't be too useful, as it should always zero during
+Lead-In... but some discs do seem return non-zero values for whatever reason).
+Aside from ADR=1, a value of ADR=5 can be used on multisession disks (eg. with
+point B0h, C0h). Not sure if any other ADR values can be used (ADR=3, ISRC is
+usually not in the Lead-In, ADR=2, EAN may be in the lead-in, but one may need
+to specify point equal to the first EAN byte).
+If the ADR/Point combination isn't found, then a timeout occurs after circa 6
+seconds (to avoid this, use GetTN to see which tracks/points exist). After the
+timeout, the command starts playing track 1. If the controller wasn't already
+in audio mode before sending the command, then it does switch off the drive
+motor for a moment (that, after the timeout, and before starting playback).
+In case of timeout, the normal INT3/INT2 responses are replaced by
+INT3/INT5/INT5 (INT3 at command start, 1st INT5 at timeout/stop, and 2nd INT5
+at restart/play).
+Note: GetQ sends scratch noise to the SPU while seeking to the Lead-In area.
+
+GetID - Command 1Ah --> INT3(stat) --> INT2/5 (stat,flags,type,atip,"SCEx")
+ Drive Status 1st Response 2nd Response
+ Door Open INT5(11h,80h) N/A
+ Spin-up INT5(01h,80h) N/A
+ Detect busy INT5(03h,80h) N/A
+ No Disk INT3(stat) INT5(08h,40h, 00h,00h, 00h,00h,00h,00h)
+ Audio Disk INT3(stat) INT5(0Ah,90h, 00h,00h, 00h,00h,00h,00h)
+ Unlicensed:Mode1 INT3(stat) INT5(0Ah,80h, 00h,00h, 00h,00h,00h,00h)
+ Unlicensed:Mode2 INT3(stat) INT5(0Ah,80h, 20h,00h, 00h,00h,00h,00h)
+ Unlicensed:Mode2+Audio INT3(stat) INT5(0Ah,90h, 20h,00h, 00h,00h,00h,00h)
+ Debug/Yaroze:Mode2 INT3(stat) INT2(02h,00h, 20h,00h, 20h,20h,20h,20h)
+ Licensed:Mode2 INT3(stat) INT2(02h,00h, 20h,00h, 53h,43h,45h,4xh)
+ Modchip:Audio/Mode1 INT3(stat) INT2(02h,00h, 00h,00h, 53h,43h,45h,4xh)
+The status byte (ie. the first byte in the responses), may differ in some
+cases; values shown above are typically received when issuing GetID shortly
+after power-up; however, shortly after the detect-busy phase, seek-busy flag
+(bit6) bit may be set, and, after issuing commands like Play/Read/Stop,
+bit7,6,5,1 may differ. The meaning of the separate 2nd response bytes is:
+ 1st byte: stat (as usually, but with bit3 same as bit7 in 2nd byte)
+ 2nd byte: flags (bit7=denied, bit4=audio... or reportedly import, uh?)
+ bit7: Licensed (0=Licensed Data CD, 1=Denied Data CD or Audio CD)
+ bit6: Missing (0=Disk Present, 1=Disk Missing)
+ bit4: Audio CD (0=Data CD, 1=Audio CD) (always 0 when Modchip installed)
+ 3rd byte: Disk type (from TOC Point=A0h) (eg. 00h=Audio or Mode1, 20h=Mode2)
+ 4th byte: Usually 00h (or 8bit ATIP from Point=C0h, if session info exists)
+ that 8bit ATIP value is taken form the middle 8bit of the 24bit ATIP value
+ 5th-8th byte: SCEx region (eg. ASCII "SCEE" = Europe) (0,0,0,0 = Unlicensed)
+The fourth letter of the "SCEx" string contains region information: "SCEI"
+(Japan/NTSC), "SCEA" (America/NTSC), "SCEE" (Europe/PAL). The "SCEx" string is
+displayed in the intro, and the PSX refuses to boot if it doesn't match up for
+the local region.
+With a modchip installed, the same response is sent for Mode1 and Audio disks
+(except for Audio disks with very short TOCs (eg. singles) because SCEX reading
+is aborted immediately after reading all TOC entries on Audio disks); whether
+it is Audio or Mode1 can be checked by examining Subchannel Q ADR/Control.Bit6
+(eg. via command 19h,60h,50h,00h).
+Yaroze does return "SCEA" for SCEA discs, but, for SCEI,SCEE,SCEW discs it does
+return four ASCII spaces (20h).
+
+CDROM - CD Audio Commands
+-------------------------
+
+To play CD-DA Audio CDs, init the following SPU Registers: CD Audio Volume,
+Main Volume, and SPU Control Bit0. Then send Demute command, and Play command.
+
+Mute - Command 0Bh --> INT3(stat)
+Turn off audio streaming to SPU (affects both CD-DA and XA-ADPCM).
+Even when muted, the CDROM controller is internally processing audio sectors
+(as seen in 1F801800h.Bit2, which works as usually for XA-ADPCM), muting is
+just forcing the CD output volume to zero.
+Mute is used by Dino Crisis 1 to mute noise during modchip detection.
+
+Demute - Command 0Ch --> INT3(stat)
+Turn on audio streaming to SPU (affects both CD-DA and XA-ADPCM). The Demute
+command is needed only if one has formerly used the Mute command (by default,
+the PSX is demuted after power-up (...and/or after Init command?), and is
+demuted after cdrom-booting).
+
+Play - Command 03h (,track) --> INT3(stat) --> optional INT1(report bytes)
+Starts CD Audio Playback. The parameter is optional, if there's no parameter
+given (or if it is 00h), then play either starts at Setloc position (if there
+was a pending unprocessed Setloc), or otherwise starts at the current location
+(eg. the last point seeked, or the current location of the current song; if it
+was already playing). For a disk with N songs, Parameters 1..N are starting the
+selected track. Parameters N+1..99h are restarting the begin of current track.
+The motor is switched off automatically when Play reaches the end of the disk,
+and INT4(stat) is generated (with stat.bit7 cleared).
+The track parameter seems to be ignored when sending Play shortly after
+power-up (ie. when the drive hasn't yet read the TOC).
+===
+"Play is almost identical to CdlReadS, believe it or not. The main difference
+is that this does not trigger a completed read IRQ. CdlPlay may be used on data
+sectors. However, all sectors from data tracks are treated as 00, so no sound
+is played. As CdlPlay is reading, the audio data appears in the sector buffer,
+but is not reliable. Game Shark "enhancement CDs" for the 2.x and 3.x versions
+used this to get around the PSX copy protection."
+Hmmm, what/where is the sector buffer... in the SPU?
+And, what/who are the 2.x and 3.x versions?
+
+Forward - Command 04h --> INT3(stat) --> optional INT1(report bytes)
+Backward - Command 05h --> INT3(stat) --> optional INT1(report bytes)
+After sending the command, the drive is in fast forward/backward mode, skipping
+every some sectors. The skipping rate is fixed (it doesn't increase after some
+seconds) (however, it increases when (as long as) sending the command again and
+again). The sound becomes (obviously) non-continous, and also rather very
+silent, muffled, and almost inaudible (that's making it rather useless; unless
+it's combined with a track/minute/second display). To terminate
+forward/backward, send a new Play command (with no parameters, so play starts
+at the "searched" location). Backward automatically switches to Play when
+reaching the begin of Track 1. Forward automatically Stops the drive motor with
+INT4(stat) when reaching the end of the last track.
+Forward/Backwards work only if the drive was in Play state, and only if Play
+had already started (ie. not shortly/immediately after a Play command); if the
+drive was not in Play state, then INT5(stat+1,80h) occurs.
+
+Setmode bits used for Play command
+During Play, only bit 7,2,1 of Setmode are used, all other Setmode bits are
+ignored (that, including bit0, ie. during Play the drive is always in CD-DA
+mode, regardless of that bit).
+Bit7 (double speed) should be usually off, although it can be used for a fast
+forward effect (with audible output). Bit2 (report) activates an optional
+interrupt for Play, Forward, and Backward commands (see below). Bit1
+(autopause) pauses play at the end of the track.
+
+Report --> INT1(stat,track,index,mm/amm,ss+80h/ass,sect/asect,peaklo,peakhi)
+With report enabled via Setmode, the Play, Forward, and Backward commands do
+repeatedly generate INT1 interrupts, with eight bytes response length. The
+interrupt isn't generated on ALL sectors, and the response changes between
+absolute time, and time within current track (the latter one indicated by bit7
+of ss):
+ amm/ass/asect are returned on asect=00h,20h,40h,60h ;-absolute time
+ mm/ss+80h/sect are returned on asect=10h,30h,50h,70h ;-within current track
+ (or, in case of read errors, report may be returned on other asect's)
+The last two response bytes (peaklo,peakhi) contain the Peak value, as received
+from the CXD2510Q Signal Processor. That is: An unsigned absolute peak level in
+lower 15bit, and an L/R flag in upper bit. The L/R bit is toggled after each
+SUBQ read, however the PSX Report mode does usually forward SUBQ only every 10
+frames (but does read SUBQ in <every> frame), so L/R will stay stuck in one
+setting (but may toggle after one second; ie. after 75 frames). And, peak is
+reset after each read, so 9 of the 10 frames are lost.
+Note: Report mode affects only CD Audio (not Data, nor XA-ADPCM sectors).
+
+AutoPause --> INT4(stat)
+Autopause can be enabled/disabled via Setmode.bit1:
+ Setmode.bit1=1: AutoPause=On --> Issue INT4(stat) and PAUSE at end of TRACK
+ Setmode.bit1=0: AutoPause=Off --> Issue INT4(stat) and STOP at end of DISC
+End of Track is determined by sensing a track number transition in SubQ
+position info. After autopause, the disc stays at the <end> of the old track,
+NOT at the <begin> of the next track (so trying to resume playing by sending a
+new Play command without new Seek/Setloc command will instantly pause again).
+Caution: SubQ track transitions may pause instantly when accidently starting to
+play at the end of the previous track rather than at begin of desired track
+(this <might> happen due to seek inaccuracies, for example, GetTD does round
+down TOC entries from MM:SS:FF to MM:SS:00, which may be off by 0.99 seconds,
+although this error should be usually compensated by the leading 2-second
+pregap/index0 region at the begin of each track, unfortunately there are a few
+.CUE sheet files that do lack both PREGAP and INDEX 00 entries on audio tracks,
+which might cause problems with autopause).
+AutoPause is used by Rayman and Tactics Ogre.
+
+Playing XA-ADPCM Sectors (compressed audio data)
+Aside from normal uncompressed CD Audio disks, the PSX can also play XA-ADPCM
+compressed sectors. XA-ADPCM sectors are organized in Files (not in tracks),
+and are "played" with Read command (not Play command).
+To play XA-ADPCM, initialize the SPU for CD Audio input (as described above),
+enable ADPCM via Setmode, then select the sector via Setloc, and issue a Read
+command (typically ReadS).
+XA-ADPCM sectors are interleaved, ie. only each Nth sector should be played
+(where "N" depends on the Motor Speed, mono/stereo format, and sample rate). If
+the "other" sectors do contain XA-ADPCM data too, then the Setfilter command
+(and XA-Filter enable flag in Setmode) must be used to select the desired
+sectors. If the "other" sectors do contain code or data (eg. MDEC video data)
+which is wanted to be send to the CPU, then SetFilter isn't required to be
+enabled (although it shouldn't disturb reading even if it is enabled).
+If XA-ADPCM (and/or XA-Filter) is enabled via Setmode, then INT1 is generated
+only for non-ADPCM sectors.
+The Setmode sector-size selection is don't care for forwarding XA-ADPCM sectors
+to the SPU (the hardware does always decompress all 900h bytes).
+
+CDROM - Test Commands
+---------------------
+
+--> CDROM - Test Commands - Version, Switches, Region, Chipset, SCEx
+--> CDROM - Test Commands - Test Drive Mechanics
+--> CDROM - Test Commands - Prototype Debug Transmission
+--> CDROM - Test Commands - Read/Write Decoder RAM and I/O Ports
+--> CDROM - Test Commands - Read HC05 SUB-CPU RAM and I/O Ports
+
+CDROM - Test Commands - Version, Switches, Region, Chipset, SCEx
+----------------------------------------------------------------
+
+19h,20h --> INT3(yy,mm,dd,ver)
+Indicates the date (Year-month-day, in BCD format) and version of the HC05
+CDROM controller BIOS. Known/existing values are:
+ (unknown) ;DTL-H2000 (with SPC700 instead HC05)
+ 94h,09h,19h,C0h ;PSX (PU-7) 19 Sep 1994, version vC0 (a)
+ 94h,11h,18h,C0h ;PSX (PU-7) 18 Nov 1994, version vC0 (b)
+ 95h,05h,16h,C1h ;PSX (LATE-PU-8) 16 May 1995, version vC1 (a)
+ 95h,07h,24h,C1h ;PSX (LATE-PU-8) 24 Jul 1995, version vC1 (b)
+ 95h,07h,24h,D1h ;PSX (LATE-PU-8,debug ver)24 Jul 1995, version vD1 (debug)
+ 96h,08h,15h,C2h ;PSX (PU-16, Video CD) 15 Aug 1996, version vC2 (VCD)
+ 96h,08h,18h,C1h ;PSX (LATE-PU-8,yaroze) 18 Aug 1996, version vC1 (yaroze)
+ 96h,09h,12h,C2h ;PSX (PU-18) (japan) 12 Sep 1996, version vC2 (a.jap)
+ 97h,01h,10h,C2h ;PSX (PU-18) (us/eur) 10 Jan 1997, version vC2 (a)
+ 97h,08h,14h,C2h ;PSX (PU-20) 14 Aug 1997, version vC2 (b)
+ 98h,06h,10h,C3h ;PSX (PU-22) 10 Jun 1998, version vC3 (a)
+ 99h,02h,01h,C3h ;PSX/PSone (PU-23, PM-41) 01 Feb 1999, version vC3 (b)
+ A1h,03h,06h,C3h ;PSone/late (PM-41(2)) 06 Jun 2001, version vC3 (c)
+ (unknown) ;PS2, xx xxx xxxx, late PS2 models...?
+
+19h,21h --> INT3(flags)
+Returns the current status of the POS0 and DOOR switches. Bit0=HeadIsAtPos0,
+Bit1=DoorIsOpen, Bit2-7=AlwaysZero.
+
+19h,22h --> INT3("for Europe")
+ Caution: Supported only in BIOS version vC1 and up. Not supported in vC0.
+Indicates the region that console is to be used in:
+ INT5(11h,10h) --> NTSC, Japan (vC0) --> requires "SCEI" discs
+ INT3("for Europe") --> PAL, Europe --> requires "SCEE" discs
+ INT3("for U/C") --> NTSC, North America --> requires "SCEA" discs
+ INT3("for Japan") --> NTSC, Japan / NTSC, Asia --> requires "SCEI" discs
+ INT3("for NETNA") --> Region-free yaroze version--> requires "SCEx" discs
+ INT3("for US/AEP") --> Region-free debug version --> accepts unlicensed CDRs
+The CDROMs must contain a matching SCEx string accordingly.
+The string "for Europe" does also suggest 50Hz PAL/SECAM video hardware.
+The Yaroze accepts any normal SCEE,SCEA,SCEI discs, plus special SCEW discs.
+
+19h,23h --> INT3("CXD2940Q/CXD1817Q/CXD2545Q/CXD1782BR") ;Servo Amplifier
+19h,24h --> INT3("CXD2940Q/CXD1817Q/CXD2545Q/CXD2510Q") ;Signal Processor
+19h,25h --> INT3("CXD2940Q/CXD1817Q/CXD1815Q/CXD1199BQ") ;Decoder/FIFO
+ Caution: Supported only in BIOS version vC1 and up. Not supported in vC0.
+Indicates the chipset that the CDROM controller is intended to be used with.
+The strings aren't always precisely correct (CXD1782BR is actually CXA1782BR,
+ie. CXA, not CXD) (and CXD1199BQ chips exist on PU-7 boards, but later PU-8
+boards do actually use CXD1815Q) (and CXD1817Q is actually CXD1817R) (and newer
+PSones are using CXD2938Q or possibly CXD2941R chips, but nothing called
+CXD2940Q).
+Note: Yaroze responds by CXD1815BQ instead of CXD1199BQ (but not by CXD1815Q).
+
+19h,04h --> INT3(stat) ;Read SCEx string (and force motor on)
+Resets the total/success counters to zero, and does then try to read the SCEx
+string from the current location (the SCEx is stored only in the Lead-In area,
+so, if the drive head is elsewhere, it will usually not find any strings,
+unless a modchip is permanently simulating SCEx strings).
+This is a raw test command (the successful or unsuccessful results do not
+lock/unlock the disk). The results can be read with command 19h,05h (which will
+terminate the SCEx reading), or they can be read from RAM with command
+19h,60h,lo,hi (which doesn't stop reading). Wait 1-2 seconds before expecting
+any results.
+Note: Like 19h,00h, this command forces the drive motor to spin at standard
+speed (synchronized with the data on the disk), works even if the shell is open
+(but stops spinning after a while if the drive is empty).
+
+19h,05h --> INT3(total,success) ;Get SCEx Counters
+Returns the total number of "Sxxx" strings received (where at least the first
+byte did match), and the number of full "SCEx" strings (where all bytes did
+match). Typically, the values are "01h,01h" for Licensed PSX Data CDs, or
+"00h,00h" for disk missing, unlicensed data CDs, Audio CDs.
+The counters are reset to zero, and SCEx receive mode is active for a few
+seconds after booting a new disk (on power up, on closing the drive door, on
+sending a Reset command, and on sub_function 04h). The disk is unlocked if the
+"success" counter is nonzero, the only exception is sub_function 04h which does
+update the counters, but does not lock/unlock the disk.
+
+CDROM - Test Commands - Test Drive Mechanics
+--------------------------------------------
+
+Signal Processor and Servo Amplifier
+
+19h,50h,msb[,mid,[lsb[,xlo]]] --> INT3(stat)
+Sends an 8bit/16bit/24bit command to the hardware, depending on number of
+parameters:
+ 1 byte --> send CX(Xx) ;short 8bit command
+ 2 bytes --> send CX(Xxxx) ;longer 16bit command
+ 3 bytes --> send CX(Xxxxxx) ;full 24bit command
+ 4 bytes --> send CX(Xxxxxxxx) ;extended 32bit command (BIOS vC3 only)
+ 4..15 bytes: acts same as max (3 or 4 bytes) (extra bytes are ignored)
+ 0 bytes or more than 15 bytes: generates an error
+
+19h,51h,msb[,mid,[lsb]] --> INT3(stat,hi,lo) ;BIOS vC2/vC3 only
+Supported by newer CDROM BIOSes only (such that use CXD2545Q or newer chips).
+Works same as 19h,50h, but does additionally receive a response.
+The command is always sending a 24bit CX(Xxxxxx) command, but it doesn't verify
+the number of parameter bytes (when using more than 3 bytes: extra bytes are
+ignored, when using less than 3 bytes: garbage is appended, which is somewhat
+valid because 8bit/16bit commands can be padded to 24bit size by appending
+"don't care" bits).
+The command can be used to send any CX(..) command, but actually it does make
+sense only for the get-status commands, see below "19h,51h,39h,xxh"
+description.
+
+19h,51h,39h,xxh --> INT3(stat,hi,lo) ;BIOS vC2/vC3 only
+Supported by newer CDROM BIOSes only (such that use CXD2545Q or newer chips).
+Sends CX(39xx) to the hardware, and receives a response (the response.hi byte
+is usually 00h for 8bit responses, or 00h..01h for 9bit responses). For
+example, this can be used to dump the Coefficient RAM.
+
+19h,03h --> INT3(stat) ;force motor off
+Forces the motor to stop spinning (ignored during spin-up phase).
+
+19h,17h --> INT3(stat) ;force motor on, clockwise, super-fast
+19h,01h --> INT3(stat) ;force motor on, anti-clockwise, super-fast
+19h,02h --> INT3(stat) ;force motor on, anti-clockwise, super-fast
+19h,10h --> INT3(stat) ;force motor on, anti-clockwise, super-fast
+19h,18h --> INT3(stat) ;force motor on, anti-clockwise, super-fast
+Forces the drive motor to spin at maximum speed (which is much faster than
+normal or double speed), in normal (clockwise), or reversed (anti-clockwise)
+direction. The commands work even if the shell is open. The commands do not try
+to synchronize the motor with the data on the disk (and do thus work even if no
+disk is inserted).
+
+19h,00h --> INT3(stat) ;force motor on, clockwise (even if shell open)
+This command seems to have effect only if the drive motor was off. If it was
+off, it does FFh-fills the TOC entries in RAM, and seek to the begin of the TOC
+at 98:30:00 or so (where minute=98 means minus two). From that location, it
+follows the spiral on the disk, although it does occassionally jump back some
+seconds. After clearing the TOC, the command does not write new data to the TOC
+buffer in RAM.
+Note: Like 19h,04h, this command forces the drive motor to spin at standard
+speed (synchronized with the data on the disk), works even if the shell is open
+(but stops spinning after a while if the drive is empty).
+
+19h,11h --> INT3(stat) ;Move Lens Up (leave parking position)
+19h,12h --> INT3(stat) ;Move Lens Down (enter parking position)
+19h,13h --> INT3(stat) ;Move Lens Outwards (away from center of disk)
+19h,14h --> INT3(stat) ;Move Lens Inwards (towards center of disk)
+Moves the laser lens. The inwards/outwards commands do move ONLY the lens (ie.
+unlike as for Seek commands, the overall-laser-unit remains in place, only the
+lens is moved).
+
+19h,15h - if motor on: move head outwards + inwards + motor off
+Moves the drive head to outer-most and inner-most position. Note that the drive
+doesn't have a switch that'd tell the controller when it has reached the
+outer-most position (so it'll forcefully hit against the outer edge) (ie. using
+this command too often may destroy the drive mechanics).
+Note: The same destructive hit-outer-edge effect happens when using Setloc/Seek
+with too large values (like minute=99h).
+
+19h,16h --> INT3(stat) ;Unknown / makes some noise if motor is on
+19h,19h --> INT3(stat) ;Unknown / no effect
+19h,1Ah --> INT3(stat) ;Unknown / makes some noise if motor is on
+Seem to have no effect?
+19h,16h seems to Move Lens Inwards, too.
+
+19h,06h,new --> INT3(old) ;Adjust balance in RAM, and apply it via CX(30+n)
+19h,07h,new --> INT3(old) ;Adjust gain in RAM, and apply it via CX(38+n)
+19h,08h,new --> INT3(old) ;Adjust balance in RAM only
+These commands are supported only by older CDROM BIOS versions (those with
+CXA1782BR Servo Amplifier).
+Later BIOSes will respond with INT5(11h,20h) when trying to use these commands
+(because CXD2545Q and later Servo Amplifiers don't support the CX(30/38+n)
+commands).
+
+CDROM - Test Commands - Prototype Debug Transmission
+----------------------------------------------------
+
+Serial Debug Messages
+Older CDROM BIOSes are supporting debug message transmission via serial bus,
+using lower 3bit of the HC05 "databus" combined with the so-called "ROMSEL" pin
+(which apparently doesn't refer to Read-Only-Memory, but rather something like
+Runtime-Output-Message, or whatever).
+Data is transferred in 24bit units (8bit command/index from HC05, followed by
+16bit data to/from HC05), bigger messages are divided into multiple such 24bit
+snippets.
+There are no connectors for external debug hardware on any PSX mainboards, so
+the whole stuff seems to be dating back to prototypes. And it seems to be
+removed from later BIOSes (which appear to use "ROMSEL" as "SCLK"; for
+receiving status info from the new CXD2545Q chips).
+
+19h,30h,index,dat1,dat2 --> INT3(stat) ;Prototype/Debug stuff
+19h,31h,dat1,dat2 --> INT3(stat) ;Prototype/Debug stuff
+19h,4xh,index --> INT3(dat1,dat2) ;Prototype/Debug stuff
+These functions are supported on older CDROM BIOS only; later BIOSes respond by
+INT5(11h,10h).
+The functions do not affect the CDROM operation (they do simple allow to
+transfer data between Main CPU and external debug hardware).
+Sub functions 30h and 31h may fail with INT5(11h,80h) when receiving wrong
+signals on the serial input line.
+Sub function "4xh" value can be 40h..4Fh (don't care).
+
+INT5 Debug Messages
+Alongsides to INT5 errors, the BIOS is usually also sending information via the
+above serial bus (the error info is divided into multiple 8bit+16bit snippets,
+and contains stat, error code, mode, current SubQ position, and most recently
+issued command).
+
+CDROM - Test Commands - Read/Write Decoder RAM and I/O Ports
+------------------------------------------------------------
+
+Caution: Below commands 19h,71h..76h are supported only in BIOS version vC1 and
+up. Not supported in vC0.
+
+19h,71h,index --> INT3(databyte) ;Read single register
+index can be 00h..1Fh, bigger values seem to be mirrored to "index AND 1Fh",
+with one exception: index 13h in NOT mirrored, instead, index 33h, 53h, 93h,
+B3h, D3h, F3h return INT5(stat+1,10h), and index 73h returns INT5(stat+1,20h).
+Aside from returning a value, the commands seem to DO something (like moving
+the drive head when a disk is inserted). Return values are usually:
+ index value
+ 00h 04h ;04h=empty, 8Eh=licensed, 24h=audio
+ 01h [0B1h] ;DCh=empty/licensed, DDh=audio
+ 02h 00h
+ 03h 00h ;or variable when disk inserted
+ 04h 00h
+ 05h 80h ;or 86h or 89h when disk inserted
+ 06h C0h
+ 07h 02h
+ 08h 8Ah
+ 09h C0h
+ 0Ah 00h
+ 0Bh C0h
+ 0Ch [1F2h]
+ 0Dh [1F3h]
+ 0Eh 00h ;or 8Eh or E6h when disk inserted ;D4h/audio
+ 0Fh 00h ;or sometimes 01h when disk inserted ;50h/audio
+ 10h C0h
+ 11h E0h
+ 12h 71h
+ 13h stat
+ 14h FFh
+ 15h..1Fh C0h-filled ;or 17h --> DEh
+
+19h,72h,index,databyte --> INT3(stat) ;Write single register
+ ;other response on param xx16h,xx18h with xx>00h
+
+19h,73h,index,len --> INT3(databytes...) ;Read multiple registers (bugged)
+19h,74h,index,len,databytes --> INT3(stat) ;Write multiple registers (bugged)
+Same as read/write single register, but trying to transfer multiple registers
+at once. BUG: The transfer should range from 00h to len-1, but the loop counter
+is left uninitialized (set to X=48h aka "command number 19h-minus-1-mul-2"
+instead of X=00h). Causing to the function to read/write garbage at index
+48h..FFh, it does then wrap to 00h and do the correct intended transfer, but
+the preceeding bugged part may have smashed RAM or I/O ports.
+
+19h,75h --> INT3(remain.lo,remain.hi,addr.lo,addr.hi) ;Get Host Xfer Info
+Returns a 4-byte value. In my early tests, on the first day it returned
+B1h,CEh,4Ch,01h, on the next day 2Ch,E4h,95h,D5h, and on all following days
+00h,C0h,00h,00h (no idea why/where the earlier values came from).
+The first byte seems to be always 00h; no matter of [1F0h].
+The second byte seems to be always C0h; no matter of [1F1h].
+The third,fourth bytes are [1F2h,1F3h].
+That two bytes are 0Ch,08h after Read commands.
+ The first bytes are NOT affected by:
+ destroying [1F0h] via too-many-parameters in command-buffer,
+ changes to [1F1h] which may occur after read command (eg. may be 20h)
+
+19h,76h,len_lo,len_hi,addr_lo,addr_hi --> INT3(stat) ;Prepare SRAM Transfer
+Prepare Transfer to/from 32K SRAM.
+After INT3, data can be read (same way as sector data after INT1).
+
+CDROM - Test Commands - Read HC05 SUB-CPU RAM and I/O Ports
+-----------------------------------------------------------
+
+19h,60h,addr_lo,addr_hi --> INT3(data) ;Read one byte from Drive RAM or I/O
+Reads one byte from the controller's RAM or I/O area, see the memory map below
+for more info. Among others, the command allows to read Subchannel Q data, eg.
+at [200h..209h], including ADR=2/UPC/EAN and ADR=3/ISRC values (which are
+suppressed by GetlocP). Eg. wait for ADR<>2, then for ADR=2, then read the
+remaining 9 bytes (because of the delayed IRQs, this works only at single
+speed) (at double speed one can read only 5 bytes before the values get
+overwritten by new data). Unknown if older boards (with 4.00MHz oscillators)
+are fast enough to read all 10 SubQ bytes.
+
+CDROM Controller I/O Area and RAM Memory Map
+First 40h bytes are I/O ports (as in MC68HC05 datasheet):
+ 000h 4 FF 7B 00 FF (other when disk inserted)
+ 004h 5 11 00 20 20 0C
+ 009h 1 00 (when disk inserted: changes between 00 or 80)
+ 00Ah 2 71 00
+ 00Ch 1 00 (when disk inserted: changes between 00 or 80)
+ 00Dh 3 20 20 20
+ 010h 8 02 80 00 60 00 00 99(orBB) 98
+ 018h 4 changes randomly (even when no disk inserted)
+ 01Ch 3 40 00 41
+ 01Fh 1 changes randomly (even when no disk inserted)
+ 020h 30 20h-filled
+ 03Eh 2 82h 20h
+Next 200h bytes are RAM:
+ 040h 4 08 00 00 00 ;or 98 07 xx 0B when disk inserted ;[40].Bit1=MUTE
+ 044h 4 00h-filled
+ 048h 3 40 20 00 ;or 58 71 0F when disk inserted
+ 04Bh 1 changes randomly (nodisk: 00 or 80 / disk: BFh)
+ 04Ch 1 Zero (or C0h)
+ 04Dh 3 MM:SS:FF (begin of current track MM:SS:00h) (or increasing addr)
+ 050h 10 Subchannel Q (adjusted position values)
+ 05Ah 2 ...
+ 05Ch 1 00h (or 64h)
+ 05Dh 3 MM:SS:FF (current read address) (sticky address during pause)
+ 060h 1 increments at circa 16Hz or so (or other rate when spinning)
+ 061h 12 00h-filled ;or else when disk inserted
+ 06Dh 1 01 ;or 0C when disk inserted
+ 06Eh 2 SetFilter setting (file,channel)
+ 070h 16 00h-filled ;or else when disk inserted
+ 080h 8 00h-filled
+ 088h 3 03:SS:FF (three, second, fraction)
+ 08Bh 3 03:SS:FF (three, second, fraction)
+ 08Eh 2 01 FF (or other values)
+ 090h 1 00h (or 91h when disk inserted + spinning)
+ 091h 13 Zero
+ 09Eh 1 00h (or 01h when disk inserted + spinning)
+ 09Fh 1 Zero
+ 0A0h 1 Always 23h
+ 0A1h 1 09h (5Dh when disk inserted)
+ 0A2h 7 00h-filled
+ 0A9h 1 40
+ 0AAh 4 00h-filled
+ 0AEh 1 00 (no disk) or 01 (disk) or so
+ 0AFh 1 00 ;or 06 when disk inserted
+ 0B0h 7 00 DC 00 02 00 E0 08 ;\or else when disk inserted
+ 0B7h 1 20 ;Bit6+7=MUTE ;
+ 0B8h 3 DE 00 00 ;/
+ 0BBh 1 SetMode setting (mode)
+ 0BCh 1 GetStat setting (stat)
+ 0BDh 3 00h-filled
+ 0C0h 6 FFh-filled ;stack... ;\
+ 0C6h 1 Usually DFh ;sometimes [0EBh and up] are non-FFh, too
+ 0C7h 15 FFh-filled ;(depending on disk or commands or so)
+ 0D6h 1 Usually FDh (or FFh) ; ;
+ 0D7h 24 FFh-filled ; stack
+ 0EFh 4 on power-up FFh-filled, other once when disk read ;
+ 0F3h 7 changes randomly (even when no disk inserted) ;
+ 0FAh 6 2E 3C 2A D6 10 95 ;/
+ 100h 2x99 TOC Entries for Start of Track 1..99 (MM:SS)
+ 1C6h 1 TOC First Track number (usually 01h)
+ 1C7h 1 TOC Last Track number (usually 01h or higher)
+ 1C8h 3 TOC Entry for Start of Lead-Out (MM:SS:FF)
+ 1CBh 2 Zero
+ 1CDh 1 Depends on disk (01 or 02 or 06) (or 00 when no disk)
+ 1CEh 1 Zero
+ 1CFh 1 Depends on disk (NULL minus N*6) (or 00 when no disk)
+ (maybe reflection level / laser intensity or so)
+ [1CDh..1CFh]
+ 01 00 E8 --> licensed/metalgear/kain
+ 01 00 EE --> licensed/alone2
+ 06 00 E2 or 00 00 02 00 E8 --> licensed/wipeout
+ 02 00 DC --> unlicensed/elo
+ 02 00 D6 --> unlicensed/driver
+ 00 00 EE --> audio/lola
+ 00 00 FA --> audio/marilyn
+ 00 00 F4 --> audio/westen
+ 00 00 00 --> disk missing
+ last byte is always in steps of 6
+ 1D0h 4 SCEx String
+ 1D4h 4 Zero
+ 1D8h 2 SCEx Counters (total,success) ;for command 19h,05h
+ 1DAh 6 00h-filled (or ... SS:FF)
+ 1E0h 6 Command Buffer (usually 19h,60h,E2h,01h = Read RAM Command)
+ 1E6h 7 00h-filled (unless destroyed by more-than-6-byte-commands)
+ 1EDh 3 Setloc setting (MM:SS:FF)
+ 1F0h 1 00h (unless destroyed by more-than-6-byte-commands)
+ 1F1h 3 C0h 00h 00h ;or 20h,0Ch,50h or C0h,0Ch,08h ;for command(19h,75h)
+ ;or 00h,00h,00h for audio
+ ;or 80h,00h,00h for disk missing
+ 1F4h 4 00h-filled ... or SCEx string
+ 1F8h 1 00h
+ 1F9h 1 Selected Target (parameter from Play and SetSession commands)
+ 1FAh 5 00h-filled ;01 01 00 8B 00 00 ;or 01 02 8B 00 00
+ 01 00 8B 00 00 -- audio/unlicensed
+ 01 01 00 00 00 -- licensed
+ 1FFh 1 00h-on power up, changes when disk inserted ;or 01 = Playing
+ 1FDh 3 MM:SS:FF (only during command 19h,00h) (MM=98..99=TOC)
+ 200h 10 Subchannel Q (real values)
+ 20Ah 2 whatever
+ 20Ch 1 Zero
+ 20Dh 1 Desired Session (from SetSession command)
+ 20Eh 1 Current Session (actual location of drive head)
+ 20Fh 1 Zero
+ 210h 10 Subchannel Q (adjusted position values)
+ 21Ah 6 00h-filled
+ 220h 4 Data Sector Header (MM:SS:FF:Mode)
+ 224h 4 Data Sector CD-XA Subheader (file,channel,sm,ci)
+ 228h 1 00h
+ 229h 1 Usually 00h (shortly other value on power-up, and maybe on seek)
+ 22Ah 1 10h (or 00h when no disk)
+ 22Bh 3 00h-filled
+ 22Eh 2 01,03 or 0A,00 or 03,01 (or else for other disk)
+ 230h 3 00h-filled (or other during spin-up / read-toc or so)
+ 233h 0Dh 00h-filled (unused RAM)
+Other/invalid addresses are:
+ 240h..2FFh - Invalid (00h-filled) (no ROM, RAM, or I/O mapped here)
+ 300h..3FFh - Mirror of 200h..2FFh ;\the BIOS is doing that
+ 400h..FFFFh - Mirrors of 000h..3FFh ;/mirroring by software
+
+Writing to RAM
+There is no command for writing to RAM. Except that, one can write to the
+command/parameter buffer at 1E0h and up. Normally, the longest known command
+should have 6 bytes (19h,76h,a,b,c,d), and longer commands results in "bad
+number of parameters" response - however, despite of that error message, the
+controller does still store ALL parameter bytes in RAM (at address 1E1h..2E0h,
+then wrapping back to 1E1h). Whereas, writing more than 16 bytes (FIFO storage
+size) will mirror the FIFO content twice, and more than 32 bytes (FIFO counter
+size) will work only when feeding extra data into the FIFO during transmission.
+Anyways, writing to 1E1h and up doesn't allow to do interesting things (such
+like manipulating the stack and executing custom code on the CPU).
+
+Subchannel Q Notes
+The "adjusted position values" at 050h, 210h, 310h contain only position
+information (with ADR=1) (the PSX seems to check only the lower 2bit of the
+4bit ADR value, so it also treats ADR=5 as ADR=1, too). Additionally, during
+Lead-In, bytes 7..9 are overwritten by the position value from bytes 3..5. The
+"real values" contain unadjusted data, including ADR=2 and ADR=3 etc.
+
+CDROM - Secret Unlock Commands
+------------------------------
+
+SecretUnlockPart1 - Command 50h --> INT5(11h,40h)
+SecretUnlockPart2 - Command 51h,"Licensed by" --> INT5(11h,40h)
+SecretUnlockPart3 - Command 52h,"Sony" --> INT5(11h,40h)
+SecretUnlockPart4 - Command 53h,"Computer" --> INT5(11h,40h)
+SecretUnlockPart5 - Command 54h,"Entertainment" --> INT5(11h,40h)
+SecretUnlockPart6 - Command 55h,<region> --> INT5(11h,40h)
+SecretUnlockPart7 - Command 56h --> INT5(11h,40h)
+ Caution: Supported only in BIOS version vC1 and up. Not supported in vC0.
+ Caution: Supported only in Europe/USA. Nonfunctional in Japan/Asia.
+ Caution: When unsupported, Parameter Fifo isn't cleared after the command.
+Sending these commands with the correct strings (in order 50h through 56h) does
+disable the "SCEx" protection. The region can be detected via test command
+19h,22h, and must be translated to the following <region> string:
+ "of America" ;for NTSC/US ;\
+ "(Europe)" ;for PAL/Europe ; handled, and actually working
+ "World wide" ;for Yaroze ;/
+ "Inc." ;for NTSC/JP ;-non-functional
+In the unlocked state, ReadN/ReadS are working for unlicensed CD-Rs, and for
+imported CDROMs from other regions (both without needing modchips). However
+there are some cases which may still cause problems: The GetID command (1Ah)
+does still identify the disc as being unlicensed, same for the Get SCEx
+Counters test command (19h,05h). And, if a game should happen to send the Reset
+command (1Ch) for some weird reason, then the BIOS would forget the unlocking,
+same for games that set the "HCRISD" I/O port bit. On the contrary,
+opening/closing the drive door does not affect the unlocking state.
+The commands have been discovered in September 2013, and appear to be supported
+by all CDROM BIOS versions (from old PSXes up to later PSones).
+Note that the commands do always respond with INT5 errors (even on successful
+unlocking).
+Japanese consoles are internally containing code for processing the Secret
+Unlock commands, but they are not actually executing that code, and even if
+they would do so: they are ignoring the resulting unlocking flag, making the
+commands nonfunctional in Japan/Asia regions.
+
+SecretLock - Command 57h --> INT5(11h,40h)
+Undoes the unlocking and restores the normal locked state (same happens when
+sending the Unlocking commands in wrong order or with wrong parameters).
+
+SecretCrash - Command 58h..5Fh --> Crash
+Jumps to a data area and executes random code. Results are more or less
+unpredictable (as they involve executing undefined opcodes). Eventually the CPU
+might hit a RET opcode and recover from the crash.
+
+CDROM - Video CD Commands
+-------------------------
+
+ Caution: Supported only on SCPH-5903, not supported on any other consoles.
+ Caution: When unsupported, Parameter Fifo isn't cleared after the command.
+
+ 1Fh VideoCD sub,a,b,c,d,e INT3(stat,a,b,c,d,e) ;<-- SCPH-5903 only
+ 1Fh..4Fh - - INT5(11h,40h) ;-Unused/invalid
+
+VideoCdSio - Cmd 1Fh,01h,JoyL,JoyH,State,Task,0 --> INT3(stat,req,mm,ss,ff,x)
+The JoyL/JoyH bytes contain 16bit button (and drive door) bits:
+ 0 Drive Door (0=Open) (from CDROM stat bit4) ;Open
+ 1 Button /\ (0=Pressed) (from PSX pad bit12) ;N/A ;PBC: Back/LevelUp
+ 2 Button [] (0=Pressed) (from PSX pad bit15) ;Enter Menu
+ 3 Button () (0=Pressed) (from PSX pad bit13) ;Leave Menu ;PBC: Confirm
+ 4 Button >< (0=Pressed) (from PSX pad bit14) ;N/A
+ 5 Start (0=Pressed) (from PSX pad bit3) ;Play/Pause
+ 6 Select (0=Pressed) (from PSX pad bit0) ;Stop (prompt restart/resume)
+ 7 Always 0 (0) (fixed) ;N/A
+ 8 DPAD Up (0=Pressed) (from PSX pad bit4) ;Menu Up ;PBC: +1
+ 9 DPAD Right (0=Pressed) (from PSX pad bit5) ;Menu Right/change ;PBC: +10
+ 10 DPAD Down (0=Pressed) (from PSX pad bit6) ;Menu Down ;PBC: -1
+ 11 DPAD Left (0=Pressed) (from PSX pad bit7) ;Menu Left/change ;PBC: -10
+ 12 Button R1 (0=Pressed) (from PSX pad bit11) ;Prev Track/Restart Track
+ 13 Button R2 (0=Pressed) (from PSX pad bit9) ;Fast Forward (slowly)
+ 14 Button L1 (0=Pressed) (from PSX pad bit10) ;Next Track (if any)
+ 15 Button L2 (0=Pressed) (from PSX pad bit8) ;Fast Backward (slowly)
+The State byte can be:
+ 00h Motor Off (or spin-up) (when stat.bit1=0)
+ 01h Playing (when stat.bit7=1)
+ 02h Paused (and not seeking) (when stat.bit6=0)
+ (note: State remains unchanged when seeking)
+The Task byte can be:
+ 00h = Confirms that "Tocread" (aka setsession 1) request was processed
+ 01h = Detect VCD Disc (used on power-up, and after door open) (after spin-up)
+ 02h = Handshake (request ack response)
+ 0Ah = Door opened during play (int5/door error)
+ 80h = No disc
+ FFh = No change (nop)
+The req byte in the INT3 response can be:
+ 00h Normal (no special event occured and no action requested)
+ 01h Request CD to Seek_and_play (using mm:ss:ff response parameter bytes)
+ 02h Request CD to Pause ;cmd(09h) -->int3(stat),int2(stat)
+ 03h Request CD to Stop ;cmd(08h) -->int3(stat),int2(stat)
+ 04h Request CD to Tocread (setsession1);cmd(12h,01h)-->int3(stat),int2(stat)
+ 05h Handshake Command was processed, and this is the "ack" response
+ 06h Request CD to Fast Forward ;cmd(04h) -->int3(stat)
+ 07h Request CD to Fast Backward ;cmd(05h) -->int3(stat)
+ 80h Detect Command was processed, and disc was detected as VCD
+ 81h Detect Command was processed, and disc was detected as Non-VCD
+
+VideoCdSwitch - Cmd 1Fh,02h,flag,x,x,x,x --> INT3(stat,0,0,x,x,x)
+ 00h = Normal PSX Mode (PortF.3=LOW) (Audio/Video from GPU/SPU chips)
+ 01h..FFh = Special VCD Mode (PortF.3=HIGH) (Audio/Video from MDEC/OSD chips)
+
+Some findings on the SC430924 firmware...
+The version/date is "15 Aug 1996, version C2h", although the "C2h" is
+misleading: The firmware is nearly identical to version "C1h" from PU-8 boards
+(the stuff added in normal "C2h" versions would be for PU-18 boards with
+different cdrom chipset).
+
+Compared to the original C1h version, there are only a few changes: A
+initialization function for initializing port F on power-up. And new command
+(command 1Fh, inserted in the various command tables), with two subfunctions
+(01h and 02h):
+- Command 1Fh,01h,a,b,c,d,e --> INT3(stat,a,b,c,d,e) Serial 5-byte read-write
+- Command 1Fh,02h,v,x,x,x,x --> INT3(stat,0,0,x,x,x) Toggle 1bit (port F.bit3)
+Whereas,
+ x = don't care/garbage
+ v = toggle state (00h=normal=PortF.3=LOW, 01h..FFh=special=PortF.3=HIGH)
+ (toggle gpu vs mpeg maybe?)
+ a,b,c,d,e = five bytes sent serially, and five bytes response received
+ serially (send/receive done simultaneously)
+
+The Port F bits are:
+ Port F.Bit0 = Serial Data In
+ Port F.Bit1 = Serial Data Out
+ Port F.Bit2 = Serial Clock Out
+ Port F.Bit3 = Toggle (0=Normal, 1=Special)
+
+And that's about all. Ie. essentially, the only change is that the new command
+controls Port F. There is no interaction with the remaining firmware (ie.
+reading, seeking, and everything is working as usually, without any video-cd
+related changes).
+The SCEx stuff is also not affected (ie. Video CDs would be seen as unlicensed
+discs, so the PSX couldn't read anything from those discs, aside from Sub-Q
+position data, of course). The SCEx region is SCEI aka "Japan" (or actually for
+Asia in this case).
+
+Note
+The SPU MUTE Flag (SPUCNT.14) does also affect VCD Audio (mute is applied to
+the final analog audio amplifier). All other SPUCNT bits can be zero for VCD.
+
+CDROM - Mainloop/Responses
+--------------------------
+
+SUB-CPU Mainloop
+The SUB-CPU is running a mainloop that is handling hardware events (by simple
+polling, not by IRQs):
+ check for incoming sectors (from CDROM decoder)
+ check for incoming commands (from Main CPU)
+ do maintenance stuff on the drive mechanics
+There is no fixed priority: if both incoming sector and incoming command are
+present, then the SUB-CPU may handle either one, depending on which portion of
+the mainloop it is currently executing.
+There is no fixed timing: if the mainloop is just checking for a specific
+event, then a new event may be processed immediately, otherwise it may take
+whole mainloop cycle until the SUB-CPU sees the event.
+Whereas, the mainloop cycle execution time isn't constant: It may vary
+depending on various details. Especially, some maintenance stuff is only
+handled approximately around 15 times per second (so there are 15 slow mainloop
+cycles per second).
+
+Responses
+The PSX can deliver one INT after another. Instead of using a real queue, it's
+merely using some flags that do indicate which INT(s) need to be delivered.
+Basically, there seem to be two flags: One for Second Response (INT2), and one
+for Data/Report Response (INT1). There is no flag for First Response (INT3);
+because that INT is generated immediately after executing a command.
+The flag mechanism means that the SUB-CPU cannot hold more than one undelivered
+INT1. That, although the CDROM Decoder does notify the SUB-CPU about all newly
+received sectors, and it can hold up to eight sectors in the 32K SRAM. However,
+the SUB-CPU BIOS merely sets a sector-delivery-needed flag (instead of
+memorizing which/how many sectors need to be delivered, and, accordingly, the
+PSX can use only three of the available eight SRAM slots: One for currently
+pending INT1, one for undelivered INT1, and one for currently/incompletly
+received sector).
+
+First Response (INT3) (or INT5 if failed)
+The first response is sent immediately after processing a command. In detail:
+The mainloop checks for incoming commands once every some clock cycles, and
+executes commands under following condition:
+ Main CPU has sent a command, AND, there is no INT pending
+ (if an INT is pending, then the command won't be executed yet, but will be
+ executed in following mainloop cycles; once when INT got acknowledged)
+ (even if no INT is pending, the mainloop may generate INT1/INT2 before
+ executing the command, if so, as said above, the command won't execute yet)
+Once when the command gets executed it will sent the first response immediately
+after the command execution (which may only take a few clock cycles, or some
+more cycles, for example Init/ReadTOC do include some time consuming
+initializations). Anyways, there will be no other INTs generated during command
+execution, so once when the command execution has started, it's guaranteed that
+the next INT will contain the first response.
+
+Second Responses (INT2) (or INT5 if failed)
+Some commands do send a second response after actual command execution:
+ 07h MotorOn E - INT3(stat), INT2(stat)
+ 08h Stop E - INT3(stat), INT2(stat)
+ 09h Pause E - INT3(stat), INT2(stat)
+ 0Ah Init - INT3(late-stat), INT2(stat)
+ 12h SetSession E session INT3(stat), INT2(stat)
+ 15h SeekL E - INT3(stat), INT2(stat) ;\use prior Setloc
+ 16h SeekP E - INT3(stat), INT2(stat) ;/to set target
+ 1Ah GetID E - INT3(stat), INT2/5(stat,flg,typ,atip,"SCEx")
+ 1Dh GetQ E adr,point INT3(stat), INT2(10bytesSubQ,peak_lo)
+ 1Eh ReadTOC - INT3(late-stat), INT2(stat)
+In some cases (like seek or spin-up), it may take more than a second until the
+2nd response is sent.
+It should be highly recommended to WAIT until the second response is generated
+BEFORE sending a new command (it wouldn't make too much sense to send a new
+command between first and second response, and results would be unknown, and
+probably totally unpredictable).
+Error Notes: If the command has been rejected (INT5 sent as 1st response) then
+the 2nd response isn't sent (eg. on wrong number of parameters, or if disc
+missing). If the command fails at a later stage (INT5 as 2nd response), then
+there are cases where another INT5 occurs as 3rd response (eg. on
+SetSession=02h on non-multisession-disk).
+
+Data/Report Responses (INT1)
+ 03h Play E (track) INT3(stat), optional INT1(report bytes)
+ 04h Forward E - INT3(stat), optional INT1(report bytes)
+ 05h Backward E - INT3(stat), optional INT1(report bytes)
+ 06h ReadN E - INT3(stat), INT1(stat), datablock
+ 1Bh ReadS E?- INT3(stat), INT1(stat), datablock
+
+CDROM - Response Timings
+------------------------
+
+Here are some response timings, measured in 33MHz units on a PAL PSone. The
+CDROM BIOSes mainloop is doing some maintenance stuff once and when, meaning
+that the response time will be higher in such mainloop cycles (max values), and
+less in normal cycles (min values). The maintenance timings do also depend on
+whether the motor is on or off (and probably on various other factors like
+seeking).
+
+First Response
+The First Response interrupt is sent almost immediately after processing the
+command (that is, when the mainloop sees a new command without any old
+interrupt pending). For GetStat, timings are as so:
+ Command Average Min Max
+ GetStat (normal) 000c4e1h 0004a73h..003115bh
+ GetStat (when stopped) 0005cf4h 000483bh..00093f2h
+Timings for most other commands should be similar as above. One exception is
+the Init command, which is doing some initialization before sending the 1st
+response:
+ Init 0013cceh 000f820h..00xxxxxh
+The ReadTOC command is doing similar initialization, and should have similar
+timing as Init command. Some (rarely used) Test commands include things like
+serial data transfers, which may be also quite slow.
+
+Second Response
+ Command Average Min Max
+ GetID 0004a00h 0004922h..0004c2bh
+ Pause (single speed) 021181ch 020eaefh..0216e3ch ;\time equal to
+ Pause (double speed) 010bd93h 010477Ah..011B302h ;/about 5 sectors
+ Pause (when paused) 0001df2h 0001d25h..0001f22h
+ Stop (single speed) 0d38acah 0c3bc41h..0da554dh
+ Stop (double speed) 18a6076h 184476bh..192b306h
+ Stop (when stopped) 0001d7bh 0001ce8h..0001eefh
+Moreover, Seek/Play/Read/SetSession/MotorOn/Init/ReadTOC are sending second
+responses which depend on seek time (and spin-up time if the motor was off).
+The seek timings are still unknown, and they are probably quite complicated:
+The CDROM BIOS seems to split seek distance somehow into coarse steps (eg.
+minutes) and fine steps (eg. seconds/sectors), so 1-minute seek distance may
+have completely different timings than 59-seconds distance.
+The amount of data per spiral winding increases towards ends of the disc (so
+the drive head will need to be moved by shorter distance when moving from
+minute 59 to 60 as than moving from 00 to 01).
+The CDROM BIOS contains some seek distance table, which is probably optimized
+for 72-minute discs (or whatever capacity is used on original PSX discs).
+80-minute CDRs may have tighter spiral windings (the above seek table is
+probably causing the drive head to be moved too far on such discs, which will
+raise the seek time as the head needs to be moved backwards to compensate that
+error).
+
+INT1 Rate
+ Command Average Min Max
+ Read (single speed) 006e1cdh 00686dah..0072732h
+ Read (double speed) 0036cd2h 00322dfh..003ab2bh
+The INT1 rate needs to be precise for CD-DA and CD-XA Audio streaming, exact
+clock cycle values should be: SystemClock*930h/4/44100Hz for Single Speed (and
+half as much for Double Speed) (the "Average" values are AVERAGE values, not
+exact values).
+
+CDROM - Response/Data Queueing
+------------------------------
+
+[Below are some older/outdated test cases]
+
+Sector Buffer
+The CDROM sector buffer is 32Kx8 SRAM (IC303). The buffer is apparently divided
+into 8 slots, theoretically allowing to buffer up to 8 sectors.
+BUG: The drive controller seems to allow only 2 of those 8 sectors (the oldest
+sector, and the current/newest sector).
+Ie. after processing the INT1 for the oldest sector, one would expect the
+controller to generate another INT1 for next newer sector - but instead it
+appears to jump directly to INT1 for the newest sector (skipping all other
+unprocessed sectors). There is no known way to get around that effect.
+So far, the big 32Kbyte buffer is entirely useless (the two accessible sectors
+could have been as well stored in a 8Kbyte chip) (unless, maybe the 32Kbytes
+have been intended for some error-correction "read-ahead" purposes, rather than
+as "look-back" buffer for old sectors; one of the unused slots might be also
+used for XA-ADPCM sectors).
+The bottom line is that one should process INT1's as soon as possible (ie.
+before the cdrom controller receives and skips further sectors). Otherwise
+sectors would be lost without notice (there appear to be absolutely no overrun
+status flags, nor overrun error interrupts).
+
+Sector Buffer Test Cases
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Process INT1 --> receives sector header for 0:2:1
+ Process INT1 --> receives sector header for 0:2:2
+ Process INT1 --> receives sector header for 0:2:3
+Above shows the normal flow when processing INT1's as they arise. Now,
+inserting delays (and not processing INT1's during that delays):
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ delay(1)
+ Process INT1 --> receives sector header for 0:2:1 (oldest sector)
+ Process INT1 --> receives sector header for 0:2:6 (newest sector)
+ Process INT1 --> receives sector header for 0:2:7 (next sector)
+Above suggests that the CDROM buffer can hold max 2 sectors (the oldest and
+current one). However, using a longer delay:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ delay(2)
+ Process INT1 --> receives sector header for 0:2:9 (oldest/overwritten)
+ Process INT1 --> receives sector header for 0:2:11 (newest sector)
+ Process INT1 --> receives sector header for 0:2:12 (next sector)
+Above indicates that sector buffer can hold 8 sectors (as the sector 1 slot is
+overwritten by sector 9). And, another test with even longer delay:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ delay(3)
+ Process INT1 --> receives sector header for 0:2:17 (currently received)
+ Process INT1 --> receives sector header for 0:2:16 (newest full sector)
+ Process INT1 --> receives sector header for 0:2:17 (next sector)
+ Process INT1 --> receives sector header for 0:2:18 (next sector)
+Above is a special case where sector 17 appears twice; the first one is the
+sector 1 slot (which was overwritten by sector 9, and apparently then half
+overwritten by sector 17).
+
+Sector Buffer VS GetlocL Response Tests
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ GetlocL
+ Process INT3 --> receives getloc info for 0:2:0
+ Process INT1 --> receives sector header for 0:2:1
+ Process INT1 --> receives sector header for 0:2:2
+ Process INT1 --> receives sector header for 0:2:3
+Another test, with Delay BEFORE Getloc:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ GetlocL
+ Process INT1 --> receives sector header for 0:2:1
+ Process INT3 --> receives getloc info for 0:2:6
+ Process INT1 --> receives sector header for 0:2:6
+ Process INT1 --> receives sector header for 0:2:7
+Another test, with Delay AFTER Getloc:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ GetlocL
+ Delay(1)
+ Process INT3 --> receives getloc info for 0:2:0
+ Process INT1 --> receives sector header for 0:2:5
+ Process INT1 --> receives sector header for 0:2:6
+ Process INT1 --> receives sector header for 0:2:7
+Another test, with Delay BEFORE and AFTER Getloc:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ GetlocL
+ Delay(1)
+ Process INT1 --> receives sector header for 0:2:9
+ Process INT1 --> receives sector header for 0:2:11
+ Process INT3 --> receives getloc info for 0:2:12
+ Process INT1 --> receives sector header for 0:2:12
+ Process INT1 --> receives sector header for 0:2:13
+
+Sector Buffer VS Pause Response Tests
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Pause
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+Another test, with Delay BEFORE Pause:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ Pause
+ Process INT1 --> receives sector header for 0:2:1 (oldest)
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+Another test, with Delay AFTER Pause:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Pause
+ Delay(1)
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+Another test, with Delay BEFORE and AFTER Pause:
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ Pause
+ Delay(1)
+ Process INT1 --> receives sector header for 0:2:9 (oldest/overwritten)
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+For above: Note that, despite of Pause, the CDROM is still writing to the
+internal buffer (and overwrites slot 1 by sector 9) (this might be because the
+Pause command isn't processed at all until INT1 is processed).
+
+Double Commands (Getloc then Pause)
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ GetlocL
+ Pause
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+Another test,
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ GetlocL
+ Pause
+ Process INT1 --> receives sector header for 0:2:1
+ Process INT1 --> receives sector header for 0:2:6
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+Another test,
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ GetlocL
+ Delay(1)
+ Pause
+ Process INT3 --> receives getloc info for 0:2:0 (first getloc response)
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+Another test,
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ GetlocL
+ Delay(1)
+ Pause
+ Process INT1 --> receives sector header for 0:2:9 (oldest/overwritten)
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT2 --> receives stat=02h (second pause response)
+
+Double Commands (Pause then Getloc)
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Pause
+ GetlocL
+ Process INT3 --> receives getloc info for 0:2:0 (first getloc response)
+ Process INT1 --> receives sector header for 0:2:1
+ Process INT1 --> receives sector header for 0:2:2
+ Process INT1 --> receives sector header for 0:2:3
+Another test,
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ Pause
+ GetlocL
+ Process INT1 --> receives sector header for 0:2:1
+ Process INT3 --> receives getloc info for 0:2:6 (first getloc response)
+ Process INT1 --> receives sector header for 0:2:6
+ Process INT1 --> receives sector header for 0:2:7
+Another test,
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Pause
+ Delay(1)
+ GetlocL
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT3 --> receives getloc info for 0:2:6 (first getloc response)
+ (No further INT's, ie. read is paused, but second-pause-response is lost).
+Another test,
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Pause
+ Delay(1)
+ GetlocL
+ Delay(1)
+ Process INT3 --> receives stat=22h (first pause response)
+ Process INT3 --> receives getloc info for 0:2:6 (first getloc response)
+ Process INT2 --> receives stat=02h (second pause response)
+Another test,
+ Setloc(0:2:0)+Read
+ Process INT1 --> receives sector header for 0:2:0
+ Delay(1)
+ Pause
+ Delay(1)
+ GetlocL
+ Process INT1 --> receives sector header for 0:2:9
+ Process INT1 --> receives sector header for 0:2:11
+ Process INT3 --> receives getloc info for 0:2:12 (first getloc response)
+ Process INT1 --> receives sector header for 0:2:12
+ Process INT1 --> receives sector header for 0:2:13
+
+CDROM Disk Format
+-----------------
+
+Overview
+The PSX uses a ISO 9660 filesystem, with data stored on CD-XA (Mode2) Sectors.
+ISO 9660 is standard for CDROM disks, although newer CDROMs may use extended
+filesystems, allowing to use long filenames and lowercase filenames, the PSX
+Kernel doesn't support such stuff, and, in fact, it's putting some restrictions
+on the ISO standard: it's limiting file names to MSDOS-style 8.3 format, and
+it's allowing only a limited number of files and directories per disk.
+
+CDROM Filesystem (ISO 9660 aka ECMA-119)
+ Originally intended for Mode1 Sectors (but is also used for CD-XA Mode2)
+ Supports "FILENAME.EXT;VERSION" filenames (version is usually "1")
+ Supports all-uppercase filenames and directory names (0-9, A-Z, underscore)
+ For PSX: Max 8-character filenames with max 3-character extensions
+ For PSX: Max 8-character directory names, without extension
+ For PSX: Max one sector per directory (?)
+ For PSX: Max one sector (or less?) per path table (?)
+
+CDROM Extended Architecture (CD-ROM XA aka CD-XA)
+ Uses Mode2 Sectors (see Sector Encoding chapter)
+ Allows 800h or 914h byte data per sector (with/without error correction)
+ Allows to break interleaved data into separate files/channels
+ Supports XA-ADPCM compressed audio data
+ Stores "CD-XA001" at 400h Primary Volume Descriptor (?)
+ Stores 14 extra bytes in System Use area (LEN_SU) of Directory Entries
+
+Physical Audio/CDROM Disk Format (ISO/IEC 10149 aka ECMA-130)
+ Defines physical metrics of the CDROM and Audio disks
+ Defines Sub-channels and Track.Index and Minute.Second.Fraction numbering
+ Defines 14bit-per-byte encoding, and splits sectors into frames
+ Defines ECC and EDC (error correction and error detection codes)
+
+Available Documentation
+ISO documents are commercial standards (not available for download), however,
+they are based on ECMA standards (which are free for download, however, the
+ECMA stuff is in PDF format, so one may treat it as commercial bullshit, too).
+CD-ROM XA is commercial only (not available for download), and, CD-XA doesn't
+seem to have become very popular outside of the PSX-world, so there's very
+little information available, portions of CD-XA are also used in the CD-i
+standard (which may be a little better or worse documented).
+
+Stuff
+ sessions one or more sessions per disk
+ tracks 99 tracks per disk (01h..99h) (usually only 01h on Data Disks)
+ index 99 indices per track (01h..99h) (rarely used, usually always 01h)
+ minutes 74 minutes per disk (00h..73h) (or more, with some restrictions)
+ seconds 60 seconds per minute (00h..59h)
+ sectors 75 sectors per second (00h..74h)
+ frames 98 frames per sector
+ bytes 33 bytes per frame (24+1+8 = data + subchannel + error correction)
+ bits 14 bits per byte (256 valid combinations, and many invalid ones)
+
+Track.Index (stored in subchannel, in BCD format)
+Multiple Tracks are usually used only on Audio Disks (one track for each song,
+numbered 01h and up), a few Audio Disks may also split Tracks into separate
+fragments with different Index values (numbered 01h and up, but most tracks
+have only Index 01h). A simple Data Disk would usually contain only one Track
+(all sectors marked Track=01h and Index=01h), although some more complex Data
+Disks may have multiple Data tracks and/or Audio tracks.
+
+Minute.Second.Sector (stored in subchannel, and in Data sectors, BCD format)
+The sectors on CDROMs and CD Audio disks are numbered in Minutes, Seconds, and
+1/75 fragments of a second (where a "second" is referring to single-speed
+drives, ie. the normal CD Audio playback speed).
+Minute.Second.Sector is stored twice in the subchannel (once the "absolute"
+time, and once the "local" time).
+The "absolute" sector number (counted from the begin of the disk) is mainly
+relevant for Seek purposes (telling the controller if the drive head is on the
+desired location, or if it needs to move the head backwards or forwards).
+The "local" sector number (counted from the begin of the track) is mainly
+relevant for Audio Players, allowing to pass the data directly to the
+Minute:Second display, without needing to subtract the start address of the
+track.
+Data disks are additionally storing the "absolute" values in their Data Areas,
+basically that's just the subchannel data duplicated, but more precisely
+assigned - the problem with the subchannel data is that the CD Audio standard
+seems to lack a clear definition that would assign the begin of the sub-channel
+block to the exact begin of a sector; so, when using only the subchannel data,
+some Drive Controllers may assign the begin of a new sector to another location
+as than other Controllers do, for Audio Disks that isn't too much of a problem,
+but for Data Disks it'd be fatal.
+
+Subchannels
+Each frame contains 8 subchannel bits (named P,Q,R,S,T,U,V,W). So, a sector
+(with 98 frames) contains 98 bits (12.25 bytes) for each subchannel.
+--> CDROM Subchannels
+
+Error Correction
+Each Frame contains 8 bytes Error Correction information, which is mainly used
+for Audio Disks, but it isn't 100% fail-proof, for that reason, Data Disks are
+containing additional Error Correction in the 930h-byte data area (the audio
+correction is probably focusing on repairing the MSBs of the 16bit samples, and
+gives less priority on the LSBs). Error Correction is some kind of a huge
+complex checksum, which allows to detect the location of faulty bytes, and to
+fix them.
+
+930h-Byte Sectors
+The "user" area for each sector is 930h bytes (2352 bytes). That region is
+combined of the 24-byte data per frame (and excludes the 8-byte audio error
+correction info, and the 1-byte subchannel data).
+Most CDROM Controllers are only giving access to this 930h-byte region (ie.
+there's no way to read the audio error correction info by software, and only
+limited access to the subchannel data, such like allowing to read only the
+Q-channel for showing track/minute/second in audio playback mode).
+On Audio disks, the 930h bytes are plain data, on Data disks that bytes are
+containing headers, error correction, and usually only 800h bytes user data
+(for more info see Sector Encoding chapter).
+
+Sessions
+Multi-Sessions are mainly used on CDR's, allowing to append newer data at the
+end of the disk at a later time. First of, the old session must contain a flag
+indicating that there may be a newer session, telling the CDROM Controller to
+search if one such exists (and if that is equally flagged, to search for an
+even newer session, and so on until reaching the last and newest session).
+Each session contains a complete new ISO Volume Descriptor, and may
+additionally contain new Path Tables, new Directories, and new Files. The
+Driver Controller is usually recursing only the Volume Descriptor of the newest
+session. However, the various Directory Records of the new session may refer to
+old files or old directories from previous sessions, allowing to "import" the
+older files, or to "rename" or "delete" them by assigning new names to that
+files, or by removing them from the directory.
+The PSX is reportedly not supporting multi-session disks, but that doesn't seem
+to be correct, namely, the Setsession command is apparently intended for that
+purpose... though not sure if the PSX Kernel is automatically searching the
+newest session... otherwise the boot executable in the first session would need
+to do that manually by software, and redirect control to the boot executable in
+the last session.
+
+CDROM Subchannels
+-----------------
+
+Subchannel P
+Subchannel P contains some kind of a Pause flag (to indicate muted areas
+between Audio Tracks). This subchannel doesn't have any checksum, so the data
+cannot be trusted to be intact (unless when sensing a longer stream of
+all-one's, or all zero's). Theoretically, the 98 pause bits are somehow
+associated to the 98 audio frames (with 24 audio bytes each) of the sector.
+However, reportedly, Subchannel P does contain two sync bits, if that is true,
+then there'd be only 96 pause flags for 98 audio frames. Strange.
+Note: Another way to indicate "paused" regions is to set Subchannel Q to ADR=1
+and Index=00h.
+
+Subchannel Q
+contains the following information:
+ Bits Expl.
+ 2 Sub-channel synchronization field
+ 8 ADR/Control (see below)
+ 72 Data (content depends on ADR)
+ 16 CRC-16-CCITT error detection code (big-endian: bytes ordered MSB, LSB)
+Possible values for the ADR/Control field are:
+ Bit0-3 ADR (0=No data, 1..3=see below, 4..0Fh=Reserved)
+ Bit4 Audio Preemphasis (0=No, 1=Yes) (Audio only, must be 0 for Data)
+ Bit5 Digital Copy (0=Prohibited, 1=Allowed)
+ Bit6 Data (0=Audio, 1=Data)
+ Bit7 Four-Channel Audio (0=Stereo, 1=Quad) (Audio only, must be 0 for Data)
+The 72bit data regions are, depending on the ADR value...
+
+Subchannel Q with ADR=1 during Lead-In -- Table of Contents (TOC)
+ 8 Track number (fixed, must be 00h=Lead-in)
+ 8 Point (01h..99h or A0h..A2h, see last three bytes for more info)
+ 24 MSF address (incrementing address within the Lead-in area)
+ Note: On some disks, these values are choosen so that the lead-in
+ <starts> at 00:00:00, on other disks so that it <ends> at 99:59:74.
+ 8 Reserved (00h)
+When Point=01h..99h (Track 1..99) or Point=A2h (Lead-Out):
+ 24 MSF address (absolute address, start address of the "Point" track)
+When Point=A0h (First Track Number):
+ 8 First Track number (BCD)
+ 8 Disk Type Byte (00h=CD-DA or CD-ROM, 10h=CD-I, 20h=CD-ROM-XA)
+ 8 Reserved (00h)
+When Point=A1h (Last Track Number):
+ 8 Last Track number (BCD)
+ 16 Reserved (0000h)
+ADR=1 should exist in 3 consecutive lead-in sectors.
+
+Subchannel Q with ADR=1 in Data region -- Position
+ 8 Track number (01h..99h=Track 1..99)
+ 8 Index number (00h=Pause, 01h..99h=Index within Track)
+ 24 Track relative MSF address (decreasing during Pause)
+ 8 Reserved (00h)
+ 24 Absolute MSF address
+ADR=1 is required to exist in at least 9 out of 10 consecutive data sectors.
+
+Subchannel Q with ADR=1 during Lead-Out -- Position
+ 8 Track number (fixed, must be AAh=Lead-Out)
+ 8 Index number (fixed, must be 01h) (there's no Index=00h in Lead-Out)
+ 24 Track relative MSF address (increasing, 00:00:00 and up)
+ 8 Reserved (00h)
+ 24 Absolute MSF address
+ADR=1 should exist in 3 consecutive lead-out sectors (and may be then followed
+by ADR=5 on multisession disks).
+
+Subchannel Q with ADR=2 -- Catalogue number of the disc (UPC/EAN barcode)
+ 52 EAN-13 barcode number (13-digit BCD)
+ 12 Reserved (000h)
+ 8 Absolute Sector number (BCD, 00h..74h) (always 00h during Lead-in)
+If the first digit of the EAN-13 number is "0", then the remaining digits are a
+UPC-A barcode number. Either the 13-digit EAN-13 number, or the 12-digit UPC-A
+number should be printed as barcode on the rear-side of the CD package.
+The first some digits contain a country code (EAN only, not UPC), followed by a
+manufacturer code, followed by a serial number. The last digit contains a
+checksum, which can be calculated as 250 minus the sum of the first 12 digits,
+minus twice the sum of each second digit, modulated by 10.
+ADR=2 isn't included on all CDs, and, many CDs do have ADR=2, but the 13 digits
+are all zero. Most CDROM drives do not allow to read EAN/UPC numbers.
+If present, ADR=2 should exist in at least 1 out of 100 consecutive sectors.
+ADR=2 may occur also in Lead-in.
+
+Subchannel Q with ADR=3 -- ISRC number of the current track
+(ISO 3901 and DIN-31-621):
+ 12 Country Code (two 6bit characters) (ASCII minus 30h) ;eg. "US"
+ 18 Owner Code (three 6bit characters) (ASCII minus 30h)
+ 2 Reserved (zero)
+ 8 Year of recording (2-digit BCD) ;eg. 82h for 1982
+ 20 Serial number (5-digit BCD) ;usually increments by 1 or 10 per track
+ 4 Reserved (zero)
+ 8 Absolute Sector number (BCD, 00h..74h) (always 00h during Lead-in)
+Most CDROM drives for PC's do not allow to read ISRC numbers (or even worse,
+they may accidently return the same ISRC number on every two tracks).
+If present, ADR=3 should exist in at least 1 out of 100 consecutive sectors.
+However, reportedly, ADR=3 should not occur in Lead-in.
+
+Subchannel Q with ADR=5 in Lead-in -- Multisession Lead-In Info
+When Point=B0h:
+ 8 Track number (fixed, must be 00h=Lead-in)
+ 8 POINT = B0h (multi-session disc)
+ 24 MM:SS:FF = the start time for the next possible session's program area,
+ a final session is indicated by FFh:FFh:FFh,
+ or when the ADR=5 / Point=B0h is absent.
+ 8 Number of different Mode-5 pointers present.
+ 24 MM:SS:FF = the maximum possible start time of the outermost Lead-out
+When Point=C0h:
+ 8 Track number (fixed, must be 00h=Lead-in)
+ 8 POINT = C0h (Identifies a Multisession disc, together with POINT=B0h)
+ 24 ATIP values from Special Information 1, ID=101
+ 8 Reserved (must be 00h)
+ 24 MM:SS:FF = Start time of the first Lead-in area of the disc
+And, optionally, when Point=C1h:
+ 8 Track number (fixed, must be 00h=Lead-in)
+ 8 POINT=C1h
+ 8x7 Copy of information from A1 point in ATIP
+
+Subchannel Q with ADR=5 in Lead-Out -- Multisession Lead-Out Info
+ 8 Track number (fixed, must be AAh=Lead-out)
+ 8 POINT = D1h (Identifies a Multisession lead-out)
+ 24 Usually zero (or maybe ATIP as in Lead-In with Point=C0h...?)
+ 8 Seems to be the session number?
+ 24 MM:SS:FF = Absolute address of the First data sector of the session
+Present in 3 consequtive sectors (3x ADR=1, 3x ADR=5, 3x ADR=1, 3x ADR=5, etc).
+
+Subchannel Q with ADR=5 in Lead-in -- CDR/CDRW Skip Info (Audio Only)
+When Point=01h..40h:
+ 8 Track number (fixed, must be 00h=Lead-in)
+ 8 POINT=01h..40h (This identifies a specific playback skip interval)
+ 24 MM:SS:FF Skip interval stop time in 6 BCD digits
+ 8 Reserved (must be 00h)
+ 24 MM:SS:FF Skip interval start time in 6 BCD digits
+When Point=B1h:
+ 8 Track number (fixed, must be 00h=Lead-in)
+ 8 POINT=B1h (Audio only: This identifies the presence of skip intervals)
+ 8x4 Reserved (must be 00h,00h,00h,00h)
+ 8 the number of skip interval pointers in POINT=01h..40h
+ 8 the number of skip track assignments in POINT=B2h..B4h
+ 8 Reserved (must be 00h)
+When Point=B2h,B3h,B4h:
+ 8 Track number (fixed, must be 00h=Lead-in)
+ 8 POINT=B2h,B3h,B4h (This identifies tracks that should be skipped)
+ 8 1st Track number to skip upon playback (01h..99h, must be nonzero)
+ 8 2nd Track number to skip upon playback (01h..99h, or 00h=None)
+ 8 3rd Track number to skip upon playback (01h..99h, or 00h=None)
+ 8 Reserved (must be 00h)... unclear... OR... 4th (of 7) skip info's...?
+ 8 4th Track number to skip upon playback (01h..99h, or 00h=None)
+ 8 5th Track number to skip upon playback (01h..99h, or 00h=None)
+ 8 6th Track number to skip upon playback (01h..99h, or 00h=None)
+Note: Skip intervals are seldom written by recorders and typically ignored by
+readers.
+
+Subchannel R..W
+Subchannels R..W are usually unused, except for some extended formats:
+ CD-TEXT in the Lead-In area (see below)
+ CD-TEXT in the Data area (rarely used)
+ CD plus Graphics (CD+G) (rarely used)
+Most CDROM drives do not allow to read these subchannels. CD-TEXT was designed
+by Sony and Philips in 1997, so it should be found only on (some) newer discs.
+Most CD/DVD players don't support it (the only exception is that CD-TEXT seems
+to be popular for car hifi equipment). Most record labels don't support
+CD-TEXT, even Sony seems to have discontinued it on their own records after
+some years (so CD-TEXT is very rare on original disks, however, CDR software
+does often allow to write CD-TEXT on CDRs).
+
+Subchannel R..W, when used for CD-TEXT in the Lead-In area
+CD-TEXT is stored in the six Subchannels R..W. Of the 12.25 bytes (98 bits) per
+subchannel, only 12 bytes are used. Together, all 6 subchannels have a capacity
+of 72 bytes (6x12 bytes) per sector. These 72 bytes are divided into four
+CD-TEXT fragments (of 18 bytes each). The format of these 18 bytes is:
+ 00h 1 Header Field ID1: Pack Type Indicator
+ 01h 1 Header Field ID2: Track Number
+ 02h 1 Header Field ID3: Sequence Number
+ 03h 1 Header Field ID4: Block Number and Character Position Indicator
+ 04h 12 Text/Data Field
+ 10h 2 CRC-16-CCITT (big-endian) (across bytes 00h..0Fh)
+ID1 - Pack Type Indicator:
+ 80h Titel (TEXT)
+ 81h Performer (TEXT)
+ 82h Songwriter (TEXT)
+ 83h Composer (TEXT)
+ 84h Arranger (TEXT)
+ 85h Message (TEXT)
+ 86h Disc ID (TEXT?) (content/format/purpose unknown?)
+ 87h Genre (BINARY) (ID codes unknown?)
+ 88h TOC (BINARY) (content/format/purpose unknown?)
+ 89h TOC2 (BINARY) (content/format/purpose unknown?)
+ 8Ah Reserved for future
+ 8Bh Reserved for future
+ 8Ch Reserved for future
+ 8Dh Reserved for "content provider" aka "closed information"
+ 8Eh UPC/EAN and ISRC Codes (TEXT) (content/format/purpose unknown?)
+ 8Fh Blocksize (BINARY) (see below)
+ID2 - Track Number:
+ 00h Title/Performer/etc. for the Disc
+ 01h..63h Title/Performer/etc. for Track 1..99 (Non-BCD) (Bit7=Extension)
+ID3 - Sequence Number:
+ 00h..FFh Incrementing Number (00h=First 18-byte fragment, 01h=Second, etc.)
+ID4 - Block Number and Character Position Indicator:
+ Bit7 Character Set (0=8bit, 1=16bit)
+ Bit6-4 Block Number (0..7 = Language number, as set by "Blocksize")
+ Bit3-0 Character Position (0..0Eh=Position, 0Fh=Append to prev fragment)
+Example Data (generated with CDRWIN):
+ ID TR SQ CH <------------Text/Data------------> -CRC- <---Text--->
+ 80 00 00 00 54 65 73 74 44 69 73 6B 54 69 74 6C E2 22 TestDiskTitl
+ 80 00 01 0C 65 00 54 65 73 74 54 72 61 63 6B 54 C9 1B e.TestTrackT
+ 80 01 02 0A 69 74 6C 65 31 00 54 65 73 74 54 72 40 3A itle1.TestTr
+ 80 02 03 06 61 63 6B 54 69 74 6C 65 32 00 00 00 80 E3 ackTitle2...
+ 81 00 04 00 54 65 73 74 44 69 73 6B 50 65 72 66 03 DF TestDiskPerf
+ 81 00 05 0C 6F 72 6D 65 72 00 54 65 73 74 54 72 12 A5 ormer.TestTr
+ 81 01 06 06 61 63 6B 50 65 72 66 6F 72 6D 65 72 BC 5B ackPerformer
+ 81 01 07 0F 31 00 54 65 73 74 54 72 61 63 6B 50 AC 41 1.TestTrackP
+ 81 02 08 0A 65 72 66 6F 72 6D 65 72 32 00 00 00 64 1A erformer2...
+ 8F 00 09 00 01 01 02 00 04 05 00 00 00 00 00 00 6D E2 ............
+ 8F 01 0A 00 00 00 00 00 00 00 00 03 0B 00 00 00 CD 0C ............
+ 8F 02 0B 00 00 00 00 00 09 00 00 00 00 00 00 00 FC 8C ............
+ 00 ;<--- for some reason, CDRWIN stores an ending 00h byte in .CDT files
+Each Text string is terminated by a 00h byte (or 0000h for 16bit character
+set). If there's still room in the 12-byte data region, then first characters
+for the next Text string (for the next track) are appended after the 00h byte
+(if there's no further track, then the remaining bytes should be padded with
+00h).
+The "Blocksize" (ID1=8Fh) consists of three packs with 24h bytes of data (first
+0Ch bytes stored with ID2=00h, next 0Ch bytes with ID2=01h, and last 0Ch bytes
+with ID2=02h):
+ 00h 1 Character set (00h,01h,80h,81h,82h = see below)
+ 01h 1 First track number (usually/always 01h)
+ 02h 1 Last track number (01h..63h)
+ 03h 1 1bit-cd-text-in-data-area-flag, 7bit-copy-protection-flags
+ 04h 16 Number of 18-byte packs for ID1=80h..8Fh
+ 14h 8 Last sequence number of block 0..7 (or 00h=none)
+ 1Ch 8 Language codes for block 0..7 (definitions are unknown)
+Character Set values (for ID1=8Fh, ID2=00h, DATA[0]=charset):
+ 00h ISO 8859-1
+ 01h ISO 646, ASCII
+ 80h MS-JIS
+ 81h Korean character code
+ 82h Mandarin (standard) Chinese character code
+ Other = reserved
+"In case the same character stings is used for consecutive tracks, character
+09h (or 0909h for 16bit charset) may be used to indicate the same as previous
+track. It shall not used for the first track."
+
+adjust_crc_16_ccitt(addr_len) ;for CD-TEXT and Subchannel Q
+ lsb=00h, msb=00h ;-initial value (zero for both CD-TEXT and Sub-Q)
+ for i=0 to len-1 ;-len (10h for CD-TEXT, 0Ah for Sub-Q)
+ x = [addr+i] xor msb
+ x = x xor (x shr 4)
+ msb = lsb xor (x shr 3) xor (x shl 4)
+ lsb = x xor (x shl 5)
+ next i
+ [addr+len+0]=msb xor FFh, [addr+len+1]=lsb xor FFh ;inverted / big-endian
+
+CDROM Sector Encoding
+---------------------
+
+Audio
+ 000h 930h Audio Data (2352 bytes) (LeftLsb,LeftMsb,RightLsb,RightMsb)
+Mode0 (Empty)
+ 000h 0Ch Sync (00h,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,00h)
+ 00Ch 4 Header (Minute,Second,Sector,Mode=00h)
+ 010h 920h Zerofilled
+Mode1 (Original CDROM)
+ 000h 0Ch Sync (00h,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,00h)
+ 00Ch 4 Header (Minute,Second,Sector,Mode=01h)
+ 010h 800h Data (2048 bytes)
+ 810h 4 EDC (checksum accross [000h..80Fh])
+ 814h 8 Zerofilled
+ 81Ch 114h ECC (error correction codes)
+Mode2/Form1 (CD-XA)
+ 000h 0Ch Sync (00h,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,00h)
+ 00Ch 4 Header (Minute,Second,Sector,Mode=02h)
+ 010h 4 Sub-Header (File, Channel, Submode AND DFh, Codinginfo)
+ 014h 4 Copy of Sub-Header
+ 018h 800h Data (2048 bytes)
+ 818h 4 EDC (checksum accross [010h..817h])
+ 81Ch 114h ECC (error correction codes)
+Mode2/Form2 (CD-XA)
+ 000h 0Ch Sync (00h,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,00h)
+ 00Ch 4 Header (Minute,Second,Sector,Mode=02h)
+ 010h 4 Sub-Header (File, Channel, Submode OR 20h, Codinginfo)
+ 014h 4 Copy of Sub-Header
+ 018h 914h Data (2324 bytes)
+ 92Ch 4 EDC (checksum accross [010h..92Bh]) (or 00000000h if no EDC)
+
+encode_sector
+ sector[000h]=00h,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh,00h
+ sector[00ch]=bcd(adr/75/60) ;0..7x
+ sector[00dh]=bcd(adr/75 MOD 60) ;0..59
+ sector[00eh]=bcd(adr MOD 75) ;0..74
+ sector[00fh]=mode
+ if mode=00h then
+ sector[010h..92Fh]=zerofilled
+ if mode=01h then
+ adjust_edc(sector+0, 800h+10h)
+ sector[814h..817h]=00h,00h,00h,00h,00h,00h,00h,00h
+ calc_p_parity(sector)
+ calc_q_parity(sector)
+ if mode=02h and form=1
+ sector[012h]=sector[012h] AND (NOT 20h) ;indicate not form2
+ sector[014h..017h]=sector[010h..013h] ;copy of sub-header
+ adjust_edc(sector+10h,800h+8)
+ push sector[00ch] ;\temporarily clear header
+ sector[00ch]=00000000h ;/
+ calc_p_parity(sector)
+ calc_q_parity(sector)
+ pop sector[00ch] ;-restore header
+ if mode=02h and form=2
+ sector[012h]=sector[012h] OR 20h ;indicate form2
+ sector[014h..017h]=sector[010h..013h] ;copy of sub-header
+ adjust_edc(sector+10h,914h+8) ;edc is optional for form2
+
+calc_parity(sector,offs,len,j0,step1,step2)
+ src=00ch, dst=81ch+offs, srcmax=dst
+ for i=0 to len-1
+ base=src, x=0000h, y=0000h
+ for j=j0 to 42
+ x=x xor GF8_PRODUCT[j,sector[src+0]]
+ y=y xor GF8_PRODUCT[j,sector[src+1]]
+ src=src+step1, if (step1=2*44) and (src>=srcmax) then src=src-2*1118
+ sector[dst+2*len+0]=x AND 0FFh, [dst+0]=x SHR 8
+ sector[dst+2*len+1]=y AND 0FFh, [dst+1]=y SHR 8
+ dst=dst+2, src=base+step2
+calc_p_parity(sector) = calc_parity(sector,0,43,19,2*43,2)
+calc_q_parity(sector) = calc_parity(sector,43*4,26,0,2*44,2*43)
+
+adjust_edc(addr,len)
+ x=00000000h
+ for i=0 to len-1
+ x=x xor byte[addr+i], x=(x shr 8) xor edc_table[x and FFh]
+ word[addr+len]=x ;append EDC value (little endian)
+
+init_tables
+ for i=0 to FFh
+ x=i, for j=0 to 7, x=x shr 1, if carry then x=x xor D8018001h
+ edc_table[i]=x
+ GF8_LOG[00h]=00h, GF8_ILOG[FFh]=00h, x=01h
+ for i=00h to FEh
+ GF8_LOG[x]=i, GF8_ILOG[i]=x
+ x=x SHL 1, if carry8bit then x=x xor 1dh
+ for j=0 to 42
+ xx=GF8_ILOG[44-j], yy=subfunc(xx xor 1,19h)
+ xx=subfunc(xx,01h), xx=subfunc(xx xor 1,18h)
+ xx=GF8_LOG[xx], yy = GF8_LOG[yy]
+ GF8_PRODUCT[j,0]=0000h
+ for i=01h to FFh
+ x=xx+GF8_LOG[i], if x>=255 then x=x-255
+ y=yy+GF8_LOG[i], if y>=255 then y=y-255
+ GF8_PRODUCT[j,i]=GF8_ILOG[x]+(GF8_ILOG[y] shl 8)
+
+subfunc(a,b)
+ if a>0 then
+ a=GF8_LOG[a]-b, if a<0 then a=a+255
+ a=GF8_ILOG[a]
+ return(a)
+
+CDROM Scrambling
+----------------
+
+Scrambling
+Scambling does XOR the data sectors with random values (done to avoid regular
+patterns). The scrambling is applied to Data sector bytes[00Ch..92Fh] (not to
+CD-DA audio sectors, and not to the leading 12-byte Sync mark in Data sectors).
+The (de-)scrambling is done automatically by the CDROM controller, so disc
+images should usually contain unscrambled data (there are some exceptions such
+like CD-i discs that have audio and data sectors mixed inside of the same
+track; which may confuse the CDROM controller about whether or not to apply
+scrambling to which sectors; so one may need to manually XOR the faulty sectors
+in the disc image).
+The scrambling pattern is derived from a 15bit polynomial counter (much like a
+noise generator in sound chips). The data bits are XORed with the counters low
+bit, and the counters lower 2bit are XORed with each other, and shifted in to
+the counters upper bit. To compute 8 bits and once, and store them in a
+924h-byte table:
+ poly=0001h ;init 15bit polynomial counter
+ for i=0 to 924h-1
+ scramble_table[i]=poly AND FFh
+ poly=(((poly XOR poly/2) AND 0FFh)*80h) XOR (poly/100h)
+ next i
+The resulting table content should be:
+ 01h,80h,00h,60h,00h,28h,00h,1Eh,80h,08h,60h,06h,A8h,02h,FEh,81h,
+ 80h,60h,60h,28h,28h,1Eh,9Eh,88h,68h,66h,AEh,AAh,FCh,7Fh,01h,E0h,
+ etc.
+After scrambling, the data is reportedly "shuffled and byte-swapped". Unknown
+what shuffling means. And unknown what/where/why byte-swapping is done (it does
+reportedly swap each two bytes in the whole(?) 930h-byte (data-?) sector; which
+might date back to different conventions for disc images to contain "16bit
+audio samples" in big- or little-endian format).
+
+CDROM XA Subheader, File, Channel, Interleave
+---------------------------------------------
+
+The Sub-Header for normal data sectors is usually 00h,00h,08h,00h (some PSX
+sectors have 09h instead 08h, indicating the end of "something" or so?
+
+1st Subheader byte - File Number (FN)
+ 0-7 File Number (00h..FFh) (for Audio/Video Interleave, see below)
+
+2nd Subheader byte - Channel Number (CN)
+ 0-4 Channel Number (00h..1Fh) (for Audio/Video Interleave, see below)
+ 5-7 Should be always zero
+Whilst not officially allowed, PSX Ace Combat 3 Electrosphere does use
+Channel=FFh for unused gaps in interleaved streaming sectors.
+
+3rd Subheader byte - Submode (SM)
+ 0 End of Record (EOR) (all Volume Descriptors, and all sectors with EOF)
+ 1 Video ;\Sector Type (usually ONE of these bits should be set)
+ 2 Audio ; Note: PSX .STR files are declared as Data (not as Video)
+ 3 Data ;/
+ 4 Trigger (for application use)
+ 5 Form2 (0=Form1/800h-byte data, 1=Form2, 914h-byte data)
+ 6 Real Time (RT)
+ 7 End of File (EOF) (or end of Directory/PathTable/VolumeTerminator)
+The EOR bit is set in all Volume Descriptor sectors, the last sector (ie. the
+Volume Descriptor Terminator) additionally has the EOF bit set. Moreover, EOR
+and EOF are set in the last sector of each Path Table, and last sector of each
+Directory, and last sector of each File.
+
+4th Subheader byte - Codinginfo (CI)
+When used for Data sectors:
+ 0-7 Reserved (00h)
+When used for XA-ADPCM audio sectors:
+ 0-1 Mono/Stereo (0=Mono, 1=Stereo, 2-3=Reserved)
+ 2-2 Sample Rate (0=37800Hz, 1=18900Hz, 2-3=Reserved)
+ 4-5 Bits per Sample (0=Normal/4bit, 1=8bit, 2-3=Reserved)
+ 6 Emphasis (0=Normal/Off, 1=Emphasis)
+ 7 Reserved (0)
+
+Audio/Video Interleave (Multiple Files/Channels)
+The CDROM drive mechanics are working best when continously following the data
+spiral on the disk, that works fine for uncompressed Audio Data at normal
+speed, but compressed Audio Data the disk is spinning much too fast. To avoid
+the drive to need to pause reading or to do permanent backwards seeking, CD-XA
+allows to store data interleaved in separate files/channels. With common
+interleave values like so:
+ Interleave Data Format
+ 1/1 (none) 44100Hz Stereo CD Audio at normal speed
+ 1/8 37800Hz Stereo ADPCM compressed Audio at double speed
+ 1/16 18900Hz Stereo ADPCM compressed Audio at double speed
+ 1/16 37800Hz Mono ADPCM compressed Audio at double speed
+ 1/32 18900Hz Mono ADPCM compressed Audio at double speed
+ 7/8 15fps 320x224 pixel MDEC compressed Videos at double speed
+ Unknown if 1/16 and 1/32 interleaves are actually possible (the PSX cdrom
+ controller seems to overwrite the IC303 sector buffer entries once every
+ eight sectors, so ADPCM data may get destroyed on interleaves above 1/8).
+ (Crash Team Racing uses 37800Hz Mono at Double speed, so 1/16 must work).
+For example, 1/8 means that the controller processes only each 8th sector (each
+having the same File Number and Channel Number), and ignores the next 7 sectors
+(which must have other File Number and/or other Channel Number). There are
+various ways to arrange multiple files or channels, for example,
+ one file with eight 1/8 audio channels
+ one file with one 1/8 audio channels, plus one 7/8 video channel (*)
+ one file with one 1/8 audio channels, plus 7 unused channels
+ eight different files with one 1/8 audio channel each
+ etc.
+(*) If the Audio and Video data belongs together then both should use the SAME
+channel.
+Note: Above interleave values are assuming that PSX Game Disks are always
+running at double speed (that's fastest for normal data files, and ADPCM files
+are usually using the same speed; otherwise it'd be neccessary to change the
+drive speed everytime when switching between Data to ADPCM modes).
+Note: The file/channel numbers can be somehow selected with the Setfilter
+command. No idea if the controller is automatically switching to the next
+channel or so when reaching the end of the file?
+
+Unused sectors in Interleave
+There are different ways to mark unused sectors in interleaved streams. Ace
+Combat 3 uses Channel=FFh=Invalid. Tron Bonne uses Submode=00h=Nothing
+(notably, that game has a 74Mbyte XA file that leaves about 75% unused).
+ Subheader bytes: 01h,FFh,64h,01h ;Ace Combat 3 Electrosphere
+ Subheader bytes: 01h,00h,00h,00h ;Misadventures of Tron Bonne (XA\*.XA)
+
+Real Time Streaming
+With the above Interleave, files can be played continously at real time - that,
+unless read-errors do occur. In that case the drive controller would usually
+perform time-consuming error-correction and/or read-retries. For video/audio
+streaming the resulting delay would be tendencially more annoying as than
+processing or skipping the incorrect data.
+In such cases the drive controller is allowed to ignore read errors; that
+probably on sectors that have the Real Time (RT) flag set in their subheaders.
+The controller is probably doing some read-ahead buffering (so, if it has
+buffered enough data, then it may still perform read retries and/or error
+correction, as long as it doesn't affect real time playback).
+
+CDROM XA Audio ADPCM Compression
+--------------------------------
+
+CD-ROM XA ADPCM is used for Audio data compression. Each 16bit sample is
+encoded in 4bit nibbles; so the compression rate is almost 1:4 (only almost 1:4
+because there are 16 header bytes within each 128-byte portion). The data is
+usually/always stored on 914h-byte sectors (without error correction).
+
+Subheader
+The Subheader (see previous chapter) contains important info for ADPCM: The
+file/channel numbers for Interleaved data, and the codinginfo flags:
+mono/stereo flag, 37800Hz/18900Hz sampling rate, 4bit/8bit format, and
+emphasis.
+
+ADPCM Sectors
+Each sector consists of 12h 128-byte portions (=900h bytes) (the remaining 14h
+bytes of the sectors 914h-byte data region are 00h filled).
+The separate 128-byte portions consist of a 16-byte header,
+ 00h..03h Copy of below 4 bytes (at 04h..07h)
+ 04h Header for 1st Block/Mono, or 1st Block/Left
+ 05h Header for 2nd Block/Mono, or 1st Block/Right
+ 06h Header for 3rd Block/Mono, or 2nd Block/Left
+ 07h Header for 4th Block/Mono, or 2nd Block/Right
+ 08h Header for 5th Block/Mono, or 3rd Block/Left ;\unknown/unused
+ 09h Header for 6th Block/Mono, or 3rd Block/Right ; for 8bit ADPCM
+ 0Ah Header for 7th Block/Mono, or 4th Block/Left ; (maybe 0, or maybe
+ 0Bh Header for 8th Block/Mono, or 4th Block/Right ;/copy of above)
+ 0Ch..0Fh Copy of above 4 bytes (at 08h..0Bh)
+followed by twentyeight data words (4x28-bytes),
+ 10h..13h 1st Data Word (packed 1st samples for 2-8 blocks)
+ 14h..17h 2nd Data Word (packed 2nd samples for 2-8 blocks)
+ 18h..1Bh 3rd Data Word (packed 3rd samples for 2-8 blocks)
+ ... Nth Data Word (packed Nth samples for 2-8 blocks)
+ 7Ch..7Fh 28th Data Word (packed 28th samples for 2-8 blocks)
+and then followed by the next 128-byte portion.
+The "Copy" bytes are allowing to repair faulty headers (ie. if the CDROM
+controller has sensed a read-error in the header then it can eventually replace
+it by the copy of the header).
+
+XA-ADPCM Header Bytes
+ 0-3 Shift (0..12) (0=Loudest) (13..15=Reserved/Same as 9)
+ 4-5 Filter (0..3) (only four filters, unlike SPU-ADPCM which has five)
+ 6-7 Unused (should be 0)
+Note: The 4bit (or 8bit) samples are expanded to 16bit by left-shifting them by
+12 (or 8), that 16bit value is then right-shifted by the selected 'shift'
+amount. For 8bit ADPCM shift should be 0..8 (values 9..12 will cut-off the
+LSB(s) of the 8bit value, this works, but isn't useful). For both 4bit and 8bit
+ADPCM, reserved shift values 13..15 will act same as shift=9).
+
+XA-ADPCM Data Words (32bit, little endian)
+ 0-3 Nibble for 1st Block/Mono, or 1st Block/Left (-8h..+7h)
+ 4-7 Nibble for 2nd Block/Mono, or 1st Block/Right (-8h..+7h)
+ 8-11 Nibble for 3rd Block/Mono, or 2nd Block/Left (-8h..+7h)
+ 12-15 Nibble for 4th Block/Mono, or 2nd Block/Right (-8h..+7h)
+ 16-19 Nibble for 5th Block/Mono, or 3rd Block/Left (-8h..+7h)
+ 20-23 Nibble for 6th Block/Mono, or 3rd Block/Right (-8h..+7h)
+ 24-27 Nibble for 7th Block/Mono, or 4th Block/Left (-8h..+7h)
+ 28-31 Nibble for 8th Block/Mono, or 4th Block/Right (-8h..+7h)
+or, for 8bit ADPCM format:
+ 0-7 Byte for 1st Block/Mono, or 1st Block/Left (-80h..+7Fh)
+ 8-15 Byte for 2nd Block/Mono, or 1st Block/Right (-80h..+7Fh)
+ 16-23 Byte for 3rd Block/Mono, or 2nd Block/Left (-80h..+7Fh)
+ 24-31 Byte for 4th Block/Mono, or 2nd Block/Right (-80h..+7Fh)
+
+decode_sector(src)
+ src=src+12+4+8 ;skip sync,header,subheader
+ for i=0 to 11h
+ for blk=0 to 3
+ IF stereo ;left-samples (LO-nibbles), plus right-samples (HI-nibbles)
+ decode_28_nibbles(src,blk,0,dst_left,old_left,older_left)
+ decode_28_nibbles(src,blk,1,dst_right,old_right,older_right)
+ ELSE ;first 28 samples (LO-nibbles), plus next 28 samples (HI-nibbles)
+ decode_28_nibbles(src,blk,0,dst_mono,old_mono,older_mono)
+ decode_28_nibbles(src,blk,1,dst_mono,old_mono,older_mono)
+ ENDIF
+ next blk
+ src=src+128
+ next i
+ src=src+14h+4 ;skip padding,edc
+
+decode_28_nibbles(src,blk,nibble,dst,old,older)
+ shift = 12 - (src[4+blk*2+nibble] AND 0Fh)
+ filter = (src[4+blk*2+nibble] AND 30h) SHR 4
+ f0 = pos_xa_adpcm_table[filter]
+ f1 = neg_xa_adpcm_table[filter]
+ for j=0 to 27
+ t = signed4bit((src[16+blk+j*4] SHR (nibble*4)) AND 0Fh)
+ s = (t SHL shift) + ((old*f0 + older*f1+32)/64);
+ s = MinMax(s,-8000h,+7FFFh)
+ halfword[dst]=s, dst=dst+2, older=old, old=s
+ next j
+
+Pos/neg Tables
+ pos_xa_adpcm_table[0..4] = (0, +60, +115, +98, +122)
+ neg_xa_adpcm_table[0..4] = (0, 0, -52, -55, -60)
+Note: XA-ADPCM supports only four filters (0..3), unlike SPU-ADPCM which
+supports five filters (0..4).
+
+Old/Older Values
+The incoming old/older values are usually that from the previous part, or
+garbage (in case of decoding errors in the previous part), or whatever (in case
+there was no previous part) (ie. maybe zero on power-up?) (and maybe there's
+also a way to reset the values to zero at the begin of a new file, or *maybe*
+it's silently done automatically when issuing seek commands?).
+
+25-point Zigzag Interpolation
+The CDROM decoder is applying some weird 25-point zigzag interpolation when
+resampling the 37800Hz XA-ADPCM output to 44100Hz. This part is different from
+SPU-ADPCM (which uses 4-point gaussian pitch interpolations). For example,
+XA-ADPCM interpolation applied to a square wave looks like this:
+ . .
+ .--------------. | | | |
+ | | .'.'.'----'.'.'.
+ | | | | | |
+ | | | |
+ | Decompressed | | Final |
+ | XA-ADPCM | | XA-ADPCM |
+ | Waveform | | Output |
+ | | | | | |
+ | | ---.'.'.' '.'.'.---
+ --------' '-------- | | | |
+ ' '
+The zigzagging does produce some (inaudible) 22050Hz noise, and does produce
+some low-pass (?) filtering ("sinc filter"). The effect can be reproduced
+somewhat like so:
+ Output37800Hz(sample):
+ ringbuf[p AND 1Fh]=sample, p=p+1, sixstep=sixstep-1
+ if sixstep=0
+ sixstep=6
+ Ouput44100Hz(ZigZagInterpolate(p,Table1))
+ Ouput44100Hz(ZigZagInterpolate(p,Table2))
+ Ouput44100Hz(ZigZagInterpolate(p,Table3))
+ Ouput44100Hz(ZigZagInterpolate(p,Table4))
+ Ouput44100Hz(ZigZagInterpolate(p,Table5))
+ Ouput44100Hz(ZigZagInterpolate(p,Table6))
+ Ouput44100Hz(ZigZagInterpolate(p,Table7))
+ endif
+ ZigZagInterpolate(p,TableX):
+ sum=0
+ for i=1 to 29, sum=sum+(ringbuf[(p-i) AND 1Fh]*TableX[i])/8000h, next i
+ return MinMax(sum,-8000h,+7FFFh)
+ Table1, Table2, Table3, Table4, Table5, Table6, Table7 ;Index
+ 0 , 0 , 0 , 0 , -0001h, +0002h, -0005h ;1
+ 0 , 0 , 0 , -0001h, +0003h, -0008h, +0011h ;2
+ 0 , 0 , -0001h, +0003h, -0008h, +0010h, -0023h ;3
+ 0 , -0002h, +0003h, -0008h, +0011h, -0023h, +0046h ;4
+ 0 , 0 , -0002h, +0006h, -0010h, +002Bh, -0017h ;5
+ -0002h, +0003h, -0005h, +0005h, +000Ah, +001Ah, -0044h ;6
+ +000Ah, -0013h, +001Fh, -001Bh, +006Bh, -00EBh, +015Bh ;7
+ -0022h, +003Ch, -004Ah, +00A6h, -016Dh, +027Bh, -0347h ;8
+ +0041h, -004Bh, +00B3h, -01A8h, +0350h, -0548h, +080Eh ;9
+ -0054h, +00A2h, -0192h, +0372h, -0623h, +0AFAh, -1249h ;10
+ +0034h, -00E3h, +02B1h, -05BFh, +0BCDh, -16FAh, +3C07h ;11
+ +0009h, +0132h, -039Eh, +09B8h, -1780h, +53E0h, +53E0h ;12
+ -010Ah, -0043h, +04F8h, -11B4h, +6794h, +3C07h, -16FAh ;13
+ +0400h, -0267h, -05A6h, +74BBh, +234Ch, -1249h, +0AFAh ;14
+ -0A78h, +0C9Dh, +7939h, +0C9Dh, -0A78h, +080Eh, -0548h ;15
+ +234Ch, +74BBh, -05A6h, -0267h, +0400h, -0347h, +027Bh ;16
+ +6794h, -11B4h, +04F8h, -0043h, -010Ah, +015Bh, -00EBh ;17
+ -1780h, +09B8h, -039Eh, +0132h, +0009h, -0044h, +001Ah ;18
+ +0BCDh, -05BFh, +02B1h, -00E3h, +0034h, -0017h, +002Bh ;19
+ -0623h, +0372h, -0192h, +00A2h, -0054h, +0046h, -0023h ;20
+ +0350h, -01A8h, +00B3h, -004Bh, +0041h, -0023h, +0010h ;21
+ -016Dh, +00A6h, -004Ah, +003Ch, -0022h, +0011h, -0008h ;22
+ +006Bh, -001Bh, +001Fh, -0013h, +000Ah, -0005h, +0002h ;23
+ +000Ah, +0005h, -0005h, +0003h, -0001h, 0 , 0 ;24
+ -0010h, +0006h, -0002h, 0 , 0 , 0 , 0 ;25
+ +0011h, -0008h, +0003h, -0002h, +0001h, 0 , 0 ;26
+ -0008h, +0003h, -0001h, 0 , 0 , 0 , 0 ;27
+ +0003h, -0001h, 0 , 0 , 0 , 0 , 0 ;28
+ -0001h, 0 , 0 , 0 , 0 , 0 , 0 ;29
+The above formula/table gives nearly correct results, but with small rounding
+errors in some cases - possibly due to actual rounding issues, or due to
+factors with bigger fractional portions, or due to a completely different
+formula...
+Probably, the hardware does actually do the above stuff in two steps: first,
+applying a zig-zag filter (with only around 21-points) to the 37800Hz output,
+and then doing 44100Hz interpolation (2-point linear or 4-point gaussian or
+whatever) in a second step.
+That two-step theory would also match well for 18900Hz resampling (which has
+lower-pitch zigzag, and gets spread accross about fifty 44100Hz samples).
+
+XA-ADPCM Emphasis
+With XA-Emphasis enabled in Sub-header, output will appear as so:
+ .------------. ....-----.
+ | | .'' |
+ | Raw | .' XA |
+ | ADPCM | | Emphasis '.
+ | Waveform | | Output '..
+ --------' '---------- --------' ''''---
+The exact XA-Emphasis formula is unknown (maybe it's just same as for CD-DA's
+SUBQ emphasis). Additionally, zig-zag interpolation is applied (somewhere
+before or after applying the emphasis stuff).
+Note: The Emphasis feature isn't used by any known PSX games.
+
+Uninitialized Six-step Counter
+The hardware does contain some six-step counter (for interpolating 37800Hz to
+44100Hz, ie. to insert one extra sample after each six samples). The 900h-byte
+sectors contain a multiple of six samples, so the counter will be always same
+before & after playing a sector. However, the initial counter value on power-up
+is uninitialized random (and the counter will fallback to that initial random
+setting after each 900h-byte sector).
+
+RIFF Headers (on PCs)
+When reading files that consist of 914h-byte sectors on a PC, the PC seems to
+automatically insert a 2Ch-byte RIFF fileheader. Like so, for ADPCM audio
+files:
+ 00h 4 "RIFF"
+ 04h 4 Total Filesize (minus 8)
+ 08h 8 "CDXAfmt "
+ 10h 4 Size of below stuff (10h)
+ 14h 14 Stuff (looks like the "LEN_SU" region from XA-Directory Record)
+ 22h 2 Zero (probably just dummy padding for 32bit alignment)
+ 24h 4 "data"
+ 28h 4 Size of following data (usually N*930h)
+That RIFF stuff isn't stored on the CDROM (at least not in the file area)
+(however, some of that info, like the "=UXA" stuff, is stored in the directory
+area of the CDROM).
+After the RIFF header, the normal sector data is appended, that, with the full
+930h bytes per sector (ie. the 914h data bytes preceeded by sync bytes, header,
+subheader, and followed by the EDC value).
+The Channel Interleave doesn't seem to be resolved, ie. the Channels are kept
+arranged as how they are stored on the CDROM. However, File Interleave <should>
+be resolved, ie. other Files that "overlap" the file shouldn't be included in
+the file.
+
+CDROM ISO Volume Descriptors
+----------------------------
+
+System Area (prior to Volume Descriptors)
+The first 16 sectors on the first track are the system area, for a Playstation
+disk, it contains the following:
+ Sector 0..3 - Zerofilled (Mode2/Form1, 4x800h bytes, plus ECC/EDC)
+ Sector 4 - Licence String
+ Sector 5..11 - Playstation Logo (3278h bytes) (remaining bytes FFh-filled)
+ Sector 12..15 - Zerofilled (Mode2/Form2, 4x914h bytes, plus EDC)
+Of which, the Licence String in sector 4 is,
+ 000h 32 Line 1 (" Licensed by ")
+ 020h 32+6 Line 2 (EU) ("Sony Computer Entertainment Euro"," pe ") ;\either
+ 020h 32+1 Line 2 (JP) ("Sony Computer Entertainment Inc.",0Ah) ; one of
+ 020h 32+6 Line 2 (US) ("Sony Computer Entertainment Amer"," ica ") ;/these
+ 041h 1983 Empty (JP) (filled by repeating pattern 62x30h,1x0Ah, 1x30h)
+ 046h 1978 Empty (EU/US) (filled by 00h-bytes)
+The Playstation Logo in sectors 5..11 contains data like so,
+ 0000h .. 41h,00h,00h,00h,00h,00h,00h,00h,01h,00h,00h,00h,1Ch,23h,00h,00h
+ 0010h .. 51h,01h,00h,00h,A4h,2Dh,00h,00h,99h,00h,00h,00h,1Ch,00h,00h,00h
+ 0020h .. ...
+ 3278h 588h FF-filled (remaining bytes on sector 11)
+the Logo contains a .TMD header, polygons, vertices and normals for the "PS"
+logo (which is displayed when booting from CDROM). Some BIOS versions are
+comparing these 3278h bytes against an identical copy in ROM, and refuse to
+boot if the data isn't 1:1 the same:
+- US/ASIA BIOS always accepts changed logos.
+- PAL BIOS accepts changed logos up to v3.0E (and refuses in v4.0E and up).
+- JP BIOS never accepts changed logos (and/or changed license strings?).
+Note: A region-patch-modchip causes PAL BIOS to behave same as US/ASIA BIOS.
+
+Volume Descriptors (Sector 16 and up)
+Playstation disks usually have only two Volume Descriptors,
+ Sector 16 - Primary Volume Descriptor
+ Sector 17 - Volume Descriptor Set Terminator
+
+Primary Volume Descriptor (sector 16 on PSX disks)
+ 000h 1 Volume Descriptor Type (01h=Primary Volume Descriptor)
+ 001h 5 Standard Identifier ("CD001")
+ 006h 1 Volume Descriptor Version (01h=Standard)
+ 007h 1 Reserved (00h)
+ 008h 32 System Identifier (a-characters) ("PLAYSTATION")
+ 028h 32 Volume Identifier (d-characters) (max 8 chars for PSX?)
+ 048h 8 Reserved (00h)
+ 050h 8 Volume Space Size (2x32bit, number of logical blocks)
+ 058h 32 Reserved (00h)
+ 078h 4 Volume Set Size (2x16bit) (usually 0001h)
+ 07Ch 4 Volume Sequence Number (2x16bit) (usually 0001h)
+ 080h 4 Logical Block Size in Bytes (2x16bit) (usually 0800h) (1 sector)
+ 084h 8 Path Table Size in Bytes (2x32bit) (max 800h for PSX)
+ 08Ch 4 Path Table 1 Block Number (32bit little-endian)
+ 090h 4 Path Table 2 Block Number (32bit little-endian) (or 0=None)
+ 094h 4 Path Table 3 Block Number (32bit big-endian)
+ 098h 4 Path Table 4 Block Number (32bit big-endian) (or 0=None)
+ 09Ch 34 Root Directory Record (see next chapter)
+ 0BEh 128 Volume Set Identifier (d-characters) (usually empty)
+ 13Eh 128 Publisher Identifier (a-characters) (company name)
+ 1BEh 128 Data Preparer Identifier (a-characters) (empty or other)
+ 23Eh 128 Application Identifier (a-characters) ("PLAYSTATION")
+ 2BEh 37 Copyright Filename ("FILENAME.EXT;VER") (empty or text)
+ 2E3h 37 Abstract Filename ("FILENAME.EXT;VER") (empty)
+ 308h 37 Bibliographic Filename ("FILENAME.EXT;VER") (empty)
+ 32Dh 17 Volume Creation Timestamp ("YYYYMMDDHHMMSSFF",timezone)
+ 33Eh 17 Volume Modification Timestamp ("0000000000000000",00h)
+ 34Fh 17 Volume Expiration Timestamp ("0000000000000000",00h)
+ 360h 17 Volume Effective Timestamp ("0000000000000000",00h)
+ 371h 1 File Structure Version (01h=Standard)
+ 372h 1 Reserved for future (00h-filled)
+ 373h 141 Application Use Area (00h-filled for PSX and VCD)
+ 400h 8 CD-XA Identifying Signature ("CD-XA001" for PSX and VCD)
+ 408h 2 CD-XA Flags (unknown purpose) (00h-filled for PSX and VCD)
+ 40Ah 8 CD-XA Startup Directory (00h-filled for PSX and VCD)
+ 412h 8 CD-XA Reserved (00h-filled for PSX and VCD)
+ 41Ah 345 Application Use Area (00h-filled for PSX and VCD)
+ 573h 653 Reserved for future (00h-filled)
+
+Volume Descriptor Set Terminator (sector 17 on PSX disks)
+ 000h 1 Volume Descriptor Type (FFh=Terminator)
+ 001h 5 Standard Identifier ("CD001")
+ 006h 1 Terminator Version (01h=Standard)
+ 007h 2041 Reserved (00h-filled)
+
+Boot Record (none such on PSX disks)
+ 000h 1 Volume Descriptor Type (00h=Boot Record)
+ 001h 5 Standard Identifier ("CD001")
+ 006h 1 Boot Record Version (01h=Standard)
+ 007h 32 Boot System Identifier (a-characters)
+ 027h 32 Boot Identifier (a-characters)
+ 047h 1977 Boot System Use (not specified content)
+
+Supplementary Volume Descriptor (none such on PSX disks)
+ 000h 1 Volume Descriptor Type (02h=Supplementary Volume Descriptor)
+ 001h .. Same as for Primary Volume Descriptor (see there)
+ 007h 1 Volume Flags (8bit)
+ 008h .. Same as for Primary Volume Descriptor (see there)
+ 058h 32 Escape Sequences (32 bytes)
+ 078h .. Same as for Primary Volume Descriptor (see there)
+In practice, this is used for Joliet:
+--> CDROM Extension Joliet
+
+Volume Partition Descriptor (none such on PSX disks)
+ 000h 1 Volume Descriptor Type (03h=Volume Partition Descriptor)
+ 001h 5 Standard Identifier ("CD001")
+ 006h 1 Volume Partition Version (01h=Standard)
+ 007h 1 Reserved (00h)
+ 008h 32 System Identifier (a-characters) (32 bytes)
+ 028h 32 Volume Partition Identifier (d-characters) (32 bytes)
+ 048h 8 Volume Partition Location (2x32bit) Logical Block Number
+ 050h 8 Volume Partition Size (2x32bit) Number of Logical Blocks
+ 058h 1960 System Use (not specified content)
+
+Reserved Volume Descriptors (none such on PSX disks)
+ 000h 1 Volume Descriptor Type (04h..FEh=Reserved, don't use)
+ 001h 2047 Reserved (don't use)
+
+CDROM ISO File and Directory Descriptors
+----------------------------------------
+
+The location of the Root Directory is described by a 34-byte Directory Record
+being located in Primary Volume Descriptor entries 09Ch..0BDh. The data therein
+is: Block Number (usually 22 on PSX disks), LEN_FI=01h, Name=00h, and,
+LEN_SU=00h (due to the 34-byte limit).
+
+Format of a Directory Record
+ 00h 1 Length of Directory Record (LEN_DR) (33+LEN_FI+pad+LEN_SU) (0=Pad)
+ 01h 1 Extended Attribute Record Length (usually 00h)
+ 02h 8 Data Logical Block Number (2x32bit)
+ 0Ah 8 Data Size in Bytes (2x32bit)
+ 12h 7 Recording Timestamp (yy-1900,mm,dd,hh,mm,ss,timezone)
+ 19h 1 File Flags 8 bits (usually 00h=File, or 02h=Directory)
+ 1Ah 1 File Unit Size (usually 00h)
+ 1Bh 1 Interleave Gap Size (usually 00h)
+ 1Ch 4 Volume Sequence Number (2x16bit, usually 0001h)
+ 20h 1 Length of Name (LEN_FI)
+ 21h LEN_FI File/Directory Name ("FILENAME.EXT;1" or "DIR_NAME" or 00h or 01h)
+ xxh 0..1 Padding Field (00h) (only if LEN_FI is even)
+ xxh LEN_SU System Use (LEN_SU bytes) (see below for CD-XA disks)
+LEN_SU can be calculated as "LEN_DR-(33+LEN_FI+Padding)". For CD-XA disks (as
+used in the PSX), LEN_SU is 14 bytes:
+ 00h 2 Owner ID Group (whatever, usually 0000h, big endian)
+ 02h 2 Owner ID User (whatever, usually 0000h, big endian)
+ 04h 2 File Attributes (big endian):
+ 0 Owner Read (usually 1)
+ 1 Reserved (0)
+ 2 Owner Execute (usually 1)
+ 3 Reserved (0)
+ 4 Group Read (usually 1)
+ 5 Reserved (0)
+ 6 Group Execute (usually 1)
+ 7 Reserved (0)
+ 8 World Read (usually 1)
+ 9 Reserved (0)
+ 10 World Execute (usually 1)
+ 11 IS_MODE2 (0=MODE1 or CD-DA, 1=MODE2)
+ 12 IS_MODE2_FORM2 (0=FORM1, 1=FORM2)
+ 13 IS_INTERLEAVED (0=No, 1=Yes...?) (by file and/or channel?)
+ 14 IS_CDDA (0=Data or ADPCM, 1=CD-DA Audio Track)
+ 15 IS_DIRECTORY (0=File or CD-DA, 1=Directory Record)
+ Commonly used Attributes are:
+ 0D55h=Normal Binary File (with 800h-byte sectors)
+ 1555h=Uncommon (fade to black .DPS and .XA files)
+ 2555h=Uncommon (wipeout .AV files) (MODE1 ??)
+ 4555h=CD-DA Audio Track (wipeout .SWP files, alone .WAV file)
+ 3D55h=Streaming File (ADPCM and/or MDEC or so)
+ 8D55h=Directory Record (parent-, current-, or sub-directory)
+ 06h 2 Signature ("XA")
+ 08h 1 File Number (Must match Subheader's File Number)
+ 09h 5 Reserved (00h-filled)
+Directory sectors do usually have zeropadding at the end of each sector:
+ - Directory sizes are always rounded up to N*800h-bytes.
+ - Directory entries should not cross 800h-byte sector boundaries.
+ There may be further directory entries on the next sector after the padding.
+ To deal with that, skip 00h-bytes until finding a nonzero LEN_DR value (or
+ slightly faster, upon a 00h-byte, directly jump to next sector instead of
+ doing a slow byte-by-byte skip).
+ Note: Padding between sectors does rarely happen on PSX discs because the
+ PSX kernel supports max 800h bytes per directory (one exception is PSX Hot
+ Shots Golf 2, which has an ISO directory with more than 800h bytes; it does
+ use a lookup file instead of actually parsing the while ISO directory).
+Names are alphabetically sorted, no matter if the names refer to files or
+directories (ie. SUBDIR would be inserted between STRFILE.EXT and SYSFILE.EXT).
+The first two entries (with non-ascii names 00h and 01h) are referring to
+current and parent directory.
+
+Path Tables
+The Path Table contain a summary of the directory names (the same information
+is also stored in the directory records, so programs may either use path tables
+or directory records; the path tables are allowing to read the whole directory
+tree quickly at once, without neeeding to seek from directory to directory).
+Path Table 1 is in Little-Endian format, Path Table 3 contains the same data in
+Big-Endian format. Path Table 2 and 4 are optional copies of Table 1 and 3. The
+size and location of the tables is stored in Volume Descriptor entries
+084h..09Bh. The format of the separate entries within a Path Table is,
+ 00h 1 Length of Directory Name (LEN_DI) (01h..08h for PSX)
+ 01h 1 Extended Attribute Record Length (usually 00h)
+ 02h 4 Directory Logical Block Number
+ 06h 2 Parent Directory Number (0001h and up)
+ 08h LEN_DI Directory Name (d-characters, d1-characters) (or 00h for Root)
+ xxh 0..1 Padding Field (00h) (only if LEN_FI is odd)
+The first entry (directory number 0001h) is the root directory, the root
+doesn't have a name, nor a parent (the name field contains a 00h byte, rather
+than ASCII text, LEN_DI is 01h, and parent is 0001h, making the root it's own
+parent; ignoring the fact that incest is forbidden in many countries).
+The next entries (directory number 0002h and up) (if any) are sub-directories
+within the root (sorted in alphabetical order, and all having parent=0001h).
+The next entries are sub-directories (if any) of the first sub-directory (also
+sorted in alphabetical order, and all having parent=0002h). And so on.
+PSX disks usually contain all four tables (usually on sectors 18,19,20,21).
+
+Format of an Extended Attribute Record (none such on PSX disks)
+If present, an Extended Attribute Record shall be recorded over at least one
+Logical Block. It shall have the following contents.
+ 00h 4 Owner Identification (numerical value) ;\used only if
+ 04h 4 Group Identification (numerical value) ; File Flags Bit4=1
+ 08h 2 Permission Flags (16bit, little-endian) ;/
+ 0Ah 17 File Creation Timestamp ("YYYYMMDDHHMMSSFF",timezone)
+ 1Bh 17 File Modification Timestamp ("0000000000000000",00h)
+ 2Ch 17 File Expiration Timestamp ("0000000000000000",00h)
+ 3Dh 17 File Effective Timestamp ("0000000000000000",00h)
+ 4Eh 1 Record Format (numerical value)
+ 4Fh 1 Record Attributes (numerical value)
+ 50h 4 Record Length (numerical value)
+ 54h 32 System Identifier (a-characters, a1-characters)
+ 74h 64 System Use (not specified content)
+ B4h 1 Extended Attribute Record Version (numerical value)
+ B5h 1 Length of Escape Sequences (LEN_ESC)
+ B6h 64 Reserved for future standardization (00h-filled)
+ F6h 4 Length of Application Use (LEN_AU)
+ FAh LEN_AU Application Use
+ xxh LEN_ESC Escape Sequences
+Unknown WHERE that data is located... the Directory Records can specify the
+Extended Attribute Length, but not the location... maybe it's meant to be
+located in the first some bytes or blocks of the File or Directory...?
+
+CDROM ISO Misc
+--------------
+
+Both Byte Order
+All 16bit and 32bit numbers in the ISO region are stored twice, once in
+Little-Endian order, and then in Big-Endian Order. For example,
+ 2x16bit value 1234h ---> stored as 34h,12h,12h,34h
+ 2x32bit value 12345678h ---> stored as 78h,56h,34h,12h,12h,34h,56h,78h
+Exceptions are the 16bit Permission Flags which are stored only in
+Little-Endian format (although the flags are four 4bit groups, so that isn't a
+real 16bit number), and, the Path Tables are stored in both formats, but
+separately, ie. one table contains only Little-Endian numbers, and the other
+only Big-Endian numbers.
+
+d-characters (Filenames)
+ "0..9", "A..Z", and "_"
+
+a-characters
+ "0..9", "A..Z", SPACE, "!"%&'()*+,-./:;<=>?_"
+Ie. all ASCII characters from 20h..5Fh except "#$@[\]^"
+
+SEPARATOR 1 = 2Eh (aka ".") (extension; eg. "EXT")
+SEPARATOR 2 = 3Bh (aka ";") (file version; "1".."32767")
+
+Fixed Length Strings/Filenames
+The Volume Descriptors contain a number fixed-length string/filename fields
+(unlike the Directory Records and Path Tables which have variable lengths).
+These fields should be padded with SPACE characters if they are empty, or if
+the string is shorter than the maximum length.
+Filename fields in Volume Descriptors are referring to files in the Root
+Directory. On PSX disks, the filename fields are usually empty, but some disks
+are mis-using the Copyright Filename to store the Company Name (although no
+such file exists on the disk).
+
+Volume Descriptor Timestamps
+The various timestamps occupy 17 bytes each, in form of
+ "YYYYMMDDHHMMSSFF",timezone
+ "0000000000000000",00h ;empty timestamp
+The first 16 bytes are ASCII Date and Time digits (Year, Month, Day, Hour,
+Minute, Second, and 1/100 Seconds. The last byte is Offset from Greenwich Mean
+Time in number of 15-minute steps from -48 (West) to +52 (East); or actually:
+to +56 when recursing Kiribati's new timezone.
+Note: PSX games manufactured in year 2000 were accidently marked to be created
+in year 0000.
+
+Recording Timestamps
+Occupy only 7 bytes, in non-ascii format
+ year-1900,month,day,hour,minute,second,timezone
+ 00h,00h,00h,00h,00h,00h,00h ;empty timestamp
+The year ranges from 1900+0 to 1900+255.
+
+File Flags
+If this Directory Record identifies a directory then bit 2,3,7 shall be set to
+ZERO.
+If no Extended Attribute Record is associated with the File Section identified
+by this Directory Record then bit positions 3 and 4 shall be set to ZERO.
+ 0 Existence (0=Normal, 1=Hidden)
+ 1 Directory (0=File, 1=Directory)
+ 2 Associated File (0=Not an Associated File, 1=Associated File)
+ 3 Record
+ If set to ZERO, shall mean that the structure of the information in
+ the file is not specified by the Record Format field of any associated
+ Extended Attribute Record (see 9.5.8).
+ If set to ONE, shall mean that the structure of the information in
+ the file has a record format specified by a number other than zero in
+ the Record Format Field of the Extended Attribute Record (see 9.5.8).
+ 4 Restrictions (0=None, 1=Restricted via Permission Flags)
+ 5 Reserved (0)
+ 6 Reserved (0)
+ 7 Multi-Extent (0=Final Directory Record for the file, 1=Not final)
+
+Permission Flags (in Extended Attribute Records)
+ 0-3 Permissions for upper-class owners
+ 4-7 Permissions for normal owners
+ 8-11 Permissions for upper-class users
+ 12-15 Permissions for normal users
+This is a bit bizarre, an upper-class owner is "an owner who is a member of a
+group of the System class of user". An upper-class user is "any user who is a
+member of the group specified by the Group Identification field". The separate
+4bit permission codes are:
+ Bit0 Permission to read the file (0=Yes, 1=No)
+ Bit1 Must be set (1)
+ Bit2 Permission to execute the file (0=Yes, 1=No)
+ Bit3 Must be set (1)
+
+CDROM Extension Joliet
+----------------------
+
+Typical Joliet Disc Header
+The discs contains two separate filesystems, the ISO one for backwards
+compatibilty, and the Joliet one with longer filenames and Unicode characters.
+ Sector 16 - Primary Volume Descriptor (with 8bit uppercase ASCII ISO names)
+ Sector 17 - Secondary Volume Descriptor (with 16bit Unicode Joliet names)
+ Sector 18 - Volume Descriptor Set Terminator
+ Sector .. - Path Tables and Directory Records (for ISO)
+ Sector .. - Path Tables and Directory Records (for Joliet)
+ Sector .. - File Data Sectors (shared for ISO and Joliet)
+There is no way to determine which ISO name belongs to which Joliet name
+(except, filenames do usually point to the same file data sectors, but that
+doesn't work for empty files, and doesn't work for folder names).
+The ISO names can be max 31 chars (or shorter for compatibility with DOS short
+names: Nero does truncate them to max 14 chars "FILENAME.EXT;1", all uppercase,
+with underscores instead of spaces, and somehow assigning names like
+"FILENAMx.EXT;1" in case of duplicated short names).
+
+Secondary Volume Descriptor (aka Supplementary Volume Descriptor)
+This is using the same format as ISO Primary Volume Descriptor (but with some
+changed entries).
+--> CDROM ISO Volume Descriptors
+Changed entries are:
+ 000h 1 Volume Descriptor Type (02h=Supplementary instead of 01h=Primary)
+ 007h 1 Volume Flags (whatever, instead of Reserved)
+ 008h 2x32 Identifier Strings (16-char Unicode instead 32-char ASCII)
+ 058h 32 Escape Sequences (see below, instead of Reserved)
+ 08Ch 4x4 Path Tables (point to new tables with Unicode chars)
+ 09Ch 34 Root Directory Record (point to root with Unicode chars)
+ 0BEh 4x128 Identifier Strings (64-char Unicode instead 128-char ASCII)
+ 2BEh 3x37 Filename Strings (18-char Unicode instead 37-char ASCII)
+The Escape Sequences entry contains three ASCII chars (plus 29-byte
+zeropadding), indicating the ISO 2022 Unicode charset:
+ %/@ UCS-2 Level 1
+ %/C UCS-2 Level 2
+ %/E UCS-2 Level 3
+
+Directory Records and Path Tables
+This is using the standard ISO format (but with 16bit Unicode characters
+instead of 8bit ASCII chars).
+--> CDROM ISO File and Directory Descriptors
+
+File and Directory Name Characters
+All characters are stored in 16bit Big Endian format. The LEN_FI filename entry
+contains the length in bytes (ie. numchars*2). Charaters 0000h/0001h are
+current/parent directory. Characters 0020h and up can be used for
+file/directory names, except six reserved characters: */:;?\
+All names must be sorted by their character numbers, padded with zero (without
+attempting to merge uppercase, lowercase, or umlauts to nearby locations).
+
+File and Directory Name Length
+ max 64 chars according to original Joliet specs from 1995
+ max 110 chars (on standard CDROMs, with LEN_SU=0)
+ max 103 chars (on CD-XA discs, with LEN_SU=14)
+Joliet Filenames include ISO-style version suffices (usually ";1", so the
+actual filename lengths are two chars less than shown above).
+The original 64-char limit was perhaps intended to leave space for future
+extensions in the LEN_SU region. The 64-char limit can cause problems with
+verbose names (eg. "Interprete - Title (version).mp3"). Microsoft later changed
+the limit to up to 110 chars.
+The 110/103-char limit is caused by the 8bit "LEN_DR=(33+LEN_FI+pad+LEN_SU)"
+entry in the Directory Records.
+Joliet allows to exceed the 8-level ISO directory nesting limit, however, it
+doesn't allow to exceed the 240-byte (120-Unicode-char) limit in ISO 9660
+section 6.8.2.1 for the total "path\filename" lengths.
+
+Official Specs
+Joliet Specification, CD-ROM Recording Spec ISO 9660:1988, Extensions for
+Unicode Version 1; May 22, 1995, Copyright 1995, Microsoft Corporation
+ http://littlesvr.ca/isomaster/resources/JolietSpecification.html
+
+CDROM File Formats
+------------------
+
+Official PSX File Formars
+--> CDROM File Official Sony File Formats
+
+Executables
+--> CDROM File Playstation EXE and SYSTEM.CNF
+--> CDROM File PsyQ .CPE Files (Debug Executables)
+--> CDROM File PsyQ .SYM Files (Debug Information)
+
+Video Files
+--> CDROM File Video Texture Image TIM/PXL/CLT (Sony)
+--> CDROM File Video Texture/Bitmap (Other)
+--> CDROM File Video 2D Graphics CEL/BGD/TSQ/ANM/SDF (Sony)
+--> CDROM File Video 3D Graphics TMD/PMD/TOD/HMD/RSD (Sony)
+--> CDROM File Video STR Streaming and BS Picture Compression (Sony)
+
+Audio Files
+--> CDROM File Audio Single Samples VAG (Sony)
+--> CDROM File Audio Sample Sets VAB and VH/VB (Sony)
+--> CDROM File Audio Sequences SEQ/SEP (Sony)
+--> CDROM File Audio Streaming XA-ADPCM
+--> CDROM File Audio CD-DA Tracks
+
+Virtual Filesystem Archives
+PSX titles are quite often using virtual filesystems, with numerous custom file
+archive formats.
+--> CDROM File Archives with Filename
+--> CDROM File Archives with Offset and Size
+--> CDROM File Archives with Offset
+--> CDROM File Archives with Size
+--> CDROM File Archives with Chunks
+--> CDROM File Archives with Folders
+--> CDROM File Archives in Hidden Sectors
+More misc stuff...
+--> CDROM File Archive HED/DAT/BNS/STR (Ape Escape)
+--> CDROM File Archive WAD.WAD, BIG.BIN, JESTERS.PKG (Crash/Herc/Pandemonium)
+--> CDROM File Archive BIGFILE.BIG (Gex)
+--> CDROM File Archive BIGFILE.DAT (Gex - Enter the Gecko)
+--> CDROM File Archive FF9 DB (Final Fantasy IX)
+--> CDROM File Archive Ace Combat 2 and 3
+--> CDROM File Archive NSD/NSF (Crash Bandicoot 1-3)
+--> CDROM File Archive STAGE.DIR and *.DAT (Metal Gear Solid)
+--> CDROM File Archive DRACULA.DAT (Dracula)
+--> CDROM File Archive Croc 1 (DIR, WAD, etc.)
+--> CDROM File Archive Croc 2 (DIR, WAD, etc.)
+--> CDROM File Archive Headerless Archives
+Using archives can avoid issues with the PSX's poorly implemented ISO
+filesystem: The PSX kernel supports max 800h bytes per directory, and lacks
+proper caching for most recently accessed directories (additionally, some
+archives can load the whole file/directory tree from continous sectors, which
+could be difficult in ISO filesystems).
+
+Compression
+--> CDROM File Compression
+
+Misc
+--> CDROM File XYZ and Dummy/Null Files
+
+FILENAME.EXT
+The BIOS seems to support only (max) 8-letter filenames with 3-letter
+extension, typically all uppercase, eg. "FILENAME.EXT". Eventually, once when
+the executable has started, some programs might install drivers for long
+filenames(?)
+
+The PSX uses the standard CDROM ISO9660 filesystem without any encryption (ie.
+you can put an original PSX CDROM into a DOS/Windows computer, and view the
+content of the files in text or hex editors without problems).
+
+Note
+MagDemoNN is short for "Official U.S. Playstation Magazine Demo Disc NN"
+
+CDROM File Official Sony File Formats
+-------------------------------------
+
+Official Sony File Formats
+https://psx.arthus.net/sdk/Psy-Q/DOCS/Devrefs/Filefrmt.pdf - Sony 1998
+ File Formats
+ (c) 1998 Sony Computer Entertainment Inc.
+ Publication date: November 1998
+ Chapter 1: Streaming Audio and Video Data
+ STR: Streaming (Movie) Data 1-3
+ BS: MDEC Bitstream Data 1-8
+ XA: CD-ROM Voice Data 1-31
+ Chapter 2: 3D Graphics
+ RSD: 3D Model Data [RSD,PLY,MAT,GRP,MSH,PVT,COD,MOT,OGP] 2-3
+ TMD: Modeling Data for OS Library 2-24
+ PMD: High-Speed Modeling Data 2-35
+ TOD: Animation Data 2-40
+ HMD: Hierarchical 3D Model, Animation and Other Data 2-49
+ Chapter 3: 2D Graphics
+ TIM: Screen Image Data 3-3
+ SDF: Sprite Editor Project File 3-8
+ PXL: Pixel Image Data 3-11
+ CLT: Palette Data 3-14
+ ANM: Animation Information 3-16
+ TSQ: Animation Time Sequence 3-22
+ CEL: Cell Data 3-23
+ BGD: BG Map Data 3-27
+ Chapter 4: Sound
+ SEQ: PS Sequence Data 4-3
+ SEP: PS Multi-Track Sequence Data 4-3
+ VAG: PS Single Waveform Data 4-5
+ VAB: PS Sound Source Data [VAB and VH/VB] 4-5
+ DA: CD-DA Data 4-7
+ Chapter 5: PDA and Memory Card
+ FAT: Memory Card File System Specification 5-3
+Most games are using their own custom file formats. However, VAG, VAB/VH(VB,
+STR/XA, and TIM are quite popular (because they are matched to the PSX
+low-level data encoding). Obviously, EXE is also very common (although not
+included in the above document).
+
+CDROM File Playstation EXE and SYSTEM.CNF
+-----------------------------------------
+
+SYSTEM.CNF
+Contains boot info in ASCII/TXT format, similar to the CONFIG.SYS or
+AUTOEXEC.BAT files for MSDOS. A typical SYSTEM.CNF would look like so:
+ BOOT = cdrom:\abcd_123.45;1 arg ;boot exe (drive:\path\name.ext;version)
+ TCB = 4 ;HEX (=4 decimal) ;max number of threads
+ EVENT = 10 ;HEX (=16 decimal) ;max number of events
+ STACK = 801FFF00 ;HEX (=memtop-256)
+The first line specifies the executable to load, from the "cdrom:" drive, "\"
+root directory, filename "abcd_123.45" (case-insensitive, the real name in the
+disk directory would be uppercase, ie. "ABCD_123.45"), and, finally ";1" is the
+file's version number (a rather strange ISO-filesystem specific feature) (the
+version number should be usually/always 1). Additionally, "arg" may contain an
+optional 128-byte command line argument string, which is copied to address
+00000180h, where it may be interpreted by the executable (most or all games
+don't use that feature).
+Each line in the file should be terminated by 0Dh,0Ah characters... not sure if
+it's also working with only 0Dh, or only 0Ah...?
+
+ABCD_123.45
+This is a normal executable (exactly as for the .EXE files, described below),
+however, the filename/extension is taken from the game code (the "ABCD-12345"
+text that is printed on the CD cover), but, with the minus replaced by an
+underscore, and due to the 8-letter filename limit, the last two characters are
+stored in the extension region.
+That "XXXX_NNN.NN" naming convention seems to apply for all official licensed
+PSX games. Wild Arms does unconventionally have the file in a separate folder,
+"EXE\SCUS_946.06".
+
+PSX.EXE (Boot-Executable) (default filename when SYSTEM.CNF doesn't exist)
+XXXX_NNN.NN (Boot-Executable) (with filename as specified in SYSTEM.CNF)
+FILENAME.EXE (General-Purpose Executable)
+PSX executables are having an 800h-byte header, followed by the code/data.
+ 000h-007h ASCII ID "PS-X EXE"
+ 008h-00Fh Zerofilled
+ 010h Initial PC (usually 80010000h, or higher)
+ 014h Initial GP/R28 (usually 0)
+ 018h Destination Address in RAM (usually 80010000h, or higher)
+ 01Ch Filesize (must be N*800h) (excluding 800h-byte header)
+ 020h Unknown/Unused ;Addr (usually 0) ;\optional overlay?
+ 024h Unknown/Unused ;Size (usually 0) ;/(not auto-loaded)
+ 028h Memfill Start Address (usually 0) (when below Size=None)
+ 02Ch Memfill Size in bytes (usually 0) (0=None)
+ 030h Initial SP/R29 & FP/R30 Base (usually 801FFFF0h) (or 0=None)
+ 034h Initial SP/R29 & FP/R30 Offs (usually 0, added to above Base)
+ 038h-04Bh Reserved for A(43h) Function (should be zerofilled in exefile)
+ 04Ch-xxxh ASCII marker
+ "Sony Computer Entertainment Inc. for Japan area"
+ "Sony Computer Entertainment Inc. for Europe area"
+ "Sony Computer Entertainment Inc. for North America area"
+ (or often zerofilled in some homebrew files)
+ (the BIOS doesn't verify this string, and boots fine without it)
+ xxxh-7FFh Zerofilled
+ 800h... Code/Data (loaded to entry[018h] and up)
+The code/data is simply loaded to the specified destination address, ie. unlike
+as in MSDOS .EXE files, there is no relocation info in the header.
+Note: In bootfiles, SP is usually 801FFFF0h (ie. not 801FFF00h as in
+system.cnf). When SP is 0, the unmodified caller's stack is used. In most cases
+(except when manually calling DoExecute), the stack values in the exeheader
+seem to be ignored though (eg. replaced by the SYSTEM.CNF value).
+The memfill region is zerofilled by a "relative" fast word-by-word fill (so
+address and size must be multiples of 4) (despite of the word-by-word filling,
+still it's SLOW because the memfill executes in uncached slow ROM).
+The reserved region at [038h-04Bh] is internally used by the BIOS to memorize
+the caller's RA,SP,R30,R28,R16 registers (for some bizarre reason, this
+information is saved in the exe header, rather than on the caller's stack).
+Additionally to the initial PC,R28,SP,R30 values that are contained in the
+header, two parameter values are passed to the executable (in R4 and R5
+registers) (however, usually that values are simply R4=1 and R5=0).
+Like normal functions, the executable can return control to the caller by
+jumping to the incoming RA address (provided that it hasn't destroyed the stack
+or other important memory locations, and that it has pushed/popped all
+registers) (returning works only for non-boot executables; if the boot
+executable returns to the BIOS, then the BIOS will simply lockup itself by
+calling the "SystemErrorBootOrDiskFailure" function.
+
+Relocatable EXE
+Fade to Black (CINE.EXR) contains ID "PS-X EXR" (instead "PS-X EXE") and string
+"PSX Relocable File - Delphine Software Int.", this is supposedly some custom
+relocatable exe file (unsupported by the PSX kernel).
+
+MSDOS.EXE and WINDOWS.EXE Files
+Some PSX discs contain DOS or Windows .EXE files (with "MZ" headers), eg.
+devkit leftovers, or demos/gimmicks.
+
+CDROM File PsyQ .CPE Files (Debug Executables)
+----------------------------------------------
+
+Fileheader
+ 00h 4 File ID (01455043h aka "CPE",01h)
+
+Chunk 00h: End of File
+ 00h 1 Chunk ID (00h)
+
+Chunk 01h: Load Data
+ 00h 1 Chunk ID (01h)
+ 01h 4 Address (usually 80010000h and up)
+ 05h 4 Size (LEN)
+ 09h LEN Data (binary EXE code/data)
+Theoretically, this could contain the whole EXE body in a single chunk.
+However, the PsyQ files are usually containing hundreds of small chunks (with
+each function and each data item in a separate chunk). For converting CPE to
+EXE, use "ExeOffset = (CpeAddress AND 1FFFFFFFh)-10000h+800h".
+
+Chunk 02h: Run Address (whatever, optional, usually not used in CPE files)
+ 00h 1 Chunk ID (02h)
+ 01h 4 Address
+Unknown what this is. It's not the entrypoint (which is set via chunk 03h).
+Maybe intended to change the default load address (usually 80010000h)?
+
+Chunk 03h: Set Value 32bit (LEN=4) (used for entrypoint)
+Chunk 04h: Set Value 16bit (LEN=2) (unused)
+Chunk 05h: Set Value 8bit (LEN=1) (unused)
+Chunk 06h: Set Value 24bit (LEN=3) (unused)
+ 00h 1 Chunk ID (03h..06h)
+ 01h 2 Register (usually 0090h=Initial PC, aka Entrypoint)
+ 03h LEN Value (8bit..32bit)
+
+Chunk 07h: Select Workspace (whatever, optional, usually not used in CPE)
+ 00h 1 Chunk ID (07h)
+ 01h 4 Workspace number (usually 00000000h)
+
+Chunk 08h: Select Unit (whatever, usually first chunk in CPE file)
+ 00h 1 Chunk ID (08h)
+ 01h 1 Unit (usually 00h)
+
+Example from LameGuy's sample.cpe:
+ 0000h 4 File ID ("CPE",01h)
+ 0004h 2 Select Unit 0 (08h,00h)
+ 0006h 7 Set Entrypoint 8001731Ch (03h,0090h,8001731Ch)
+ 000Dh 0Dh Load (01h,800195F8h,00000004h,0,0,0,0)
+ 001Ah .. Load (01h,80010000h,0000002Bh,...)
+ 004Eh .. Load (01h,8001065Ch,00000120h,...)
+ 0177h ... Load (01h,8001077Ch,0000012Ch,...)
+ 02ACh ... Load (01h,800108A8h,000000A4h,...)
+ ... ... Load (...)
+ 98F4h ... Load (01h,800195F0h,00000008h,...)
+ 9905h 1 End (00h)
+
+CDROM File PsyQ .SYM Files (Debug Information)
+----------------------------------------------
+
+PsyQ .SYM Files contain debug info, usually bundled with PsyQ .MAP and Psy .CPE
+files. Those files are generated by PsyQ tools, which appear to be still in use
+for homebrew PSX titles.
+The files are occassionally also found on PSX CDROMs:
+ Legacy of Kain PAL version (\DEGUG\NTSC\KAIN2.SYM+MAP+CPE)
+ RC Revenge (\RELEASE.SYM)
+ Twisted Metal: Small Brawl (MagDemo54: TMSB\TM.SYM)
+ Jackie Chan Stuntmaster (GAME_REL.SYM+CPE)
+ SnoCross Championship Racing (MagDemo37: SNOCROSS\SNOW.TOC\SNOW.MAP)
+ Sled Storm (MagDemo24: DEBUG\MAIN.MAP)
+ E.T. Interplanetary Mission (MagDemo54: MEGA\MEGA.CSH\* has SYM+CPE+MAP)
+
+Fileheader .SYM
+ 00h 4 File ID ("MND",01h)
+ 04h 4 Whatever (0,0,0,0) ;TOMB5: 0,02h,0,0
+ 08h .. Chunks (see below)
+
+ _______________________________ Symbol Chunks ________________________________
+
+Chunk 01h: Symbol (Immediate, eg. memsize, or membase)
+Chunk 02h: Symbol (Function Address for Internal & External Functions)
+Chunk 05h: Symbol (?)
+Chunk 06h: Symbol (?)
+ 00h 4 Address/Value
+ 04h 1 Chunk ID (01h/02h/05h/06h)
+ 05h 1 Symbol Length (LEN)
+ 06h LEN Symbol (eg. "VSync")
+
+ __________________________ Source Code Line Chunks ___________________________
+
+Chunk 80h: Source Code Line Numbers: Address for 1 Line
+ 00h 4 Address (for 1 line, starting at current line)
+ 04h 1 Chunk ID (80h)
+
+Chunk 82h: Source Code Line Numbers: Address for N Lines (8bit)
+ 00h 4 Address (for N lines, starting at current line)
+ 04h 1 Chunk ID (82h)
+ 05h 1 Number of Lines (00h=None, or 02h and up?)
+
+Chunk 84h: Source Code Line Numbers: Address for NN Lines (16bit)
+ 00h 4 Address (for N lines, starting at current line)
+ 04h 1 Chunk ID (84h)
+ 05h 2 Number of Lines (?)
+
+Chunk 86h: Source Code Line Numbers: Address for Line NNN (32bit?)
+ 00h 4 Address (for 1 line, starting at newly assigned current line)
+ 04h 1 Chunk ID (84h)
+ 05h 4 Absolute Line Number (rather than number of lines) (?)
+
+Chunk 88h: Source Code Line Numbers: Start with Filename
+ 00h 4 Address (start address)
+ 04h 1 Chunk ID (88h=Filename)
+ 05h 4 First Line Number (after comments/definitions) (32bit?)
+ 09h 1 Filename Length (LEN)
+ 0Ah LEN Filename (eg. "C:\path\main.c")
+
+Chunk 8Ah: Source Code Line Numbers: End of Source Code
+ 00h 4 Address (end address)
+ 04h 1 Chunk ID (8Ah)
+
+ __________________________ Internal Function Chunks __________________________
+
+Chunk 8Ch: Internal Function: Start with Filename
+ 00h 4 Address
+ 04h 1 Chunk ID (8Ch)
+ 05h 4 Whatever (1Eh,00h,20h,00h) ;or 1Eh,00h,18h,00h
+ 09h 4 Whatever (00h,00h,1Fh,00h)
+ 0Dh 4 Whatever (00h,00h,00h,C0h)
+ 11h 4 Whatever (FCh,FFh,FFh,FFh) ;mask? neg.offset?
+ 15h 4 Whatever (10h,00h,00h,00h) <-- line number (32bit?)
+ 19h 1 Filename Length (LEN1)
+ 1Ah LEN1 Filename (eg. "C:\path\main.c")
+ xxh 1 Symbol Length (LEN2)
+ xxh LEN2 Symbol (eg. "VSync")
+
+Chunk 8Eh: Internal Function: End of Function (end of chunk 8Ch)
+ 00h 4 Address
+ 04h 1 Chunk ID (8Eh)
+ 05h 4 Line Number <-- line number (32bit?)
+
+Chunk 90h: Internal Function:Whatever90h... first instruction in main func?
+Chunk 92h: Internal Function:Whatever92h... last instruction in main func?
+Maybe line numbers? Or end of definitions for incoming parameters?
+ 00h 4 Address
+ 04h 1 Chunk ID (90h/92h)
+ 05h 4 Whatever (1Fh,00h,00h,00h) <-- line number relative to main.start?
+
+ _____________________________ Class/Type Chunks ______________________________
+
+Chunk 94h: Type/Symbol (Simple Types?)
+ 00h 4 Offset (when used within a structure, or stack-N, or otherwise zero)
+ 04h 1 Chunk ID (94h)
+ 05h 2 Class (000Dh=Type.alias, 000Ah=Address, 0001h=Stack, 0002h=Addr)
+ 07h 2 Type (XX = 8bit,16bit,signed,etc.?)
+ 09h 4 Zero, or Size in Bytes (for "memblocks")
+ 0xh 1 Symbol Name Length (LEN)
+ 0xh LEN Symbol Name (eg. "size_t")
+
+Chunk 96h: Type/Symbol (Complex Structures/Arrays?)
+ 00h 4 Offset (when used within a structure, otherwise zero)
+ 04h 1 Chunk ID (96h)
+ 05h 2 Class (02h=Array,08h=RefToStruct,0Dh=DefineAlias,66h=StructEnd)
+ 07h 2 Type (0xh=Small, 3xh=WithArrayStuff?) (same/similar as in chunk 94h)
+ 09h 4 Struct Size in Bytes
+ 0Dh 2 Array Dimensions (DIM) (0=none) ;eg. [3][4] --> 0002h
+ 0Fh DIM*4 Array Entries per Dimension ;eg. [3][4] --> 00000003h,00000004h
+ xxh 1 Internal Fake Name Length (LEN1) (0=none)
+ xxh LEN1 Internal Fake Name (eg. ".1fake")
+ xxh 1 Symbol Name Length (LEN2)
+ xxh LEN2 Symbol Name (eg. "r")
+
+ ______________________________ Class/Type Values _____________________________
+
+Class definition (in chunk 94h) (and somewhat same/similar in chunk 96h)
+(looks same/similar as C_xxx class values in COFF files!)
+ 0001h = Local variable (with Offset = negative stack offset)
+ 0002h = Global variable or Function (with Offset = address)
+ 0008h = Item in Structure (with Offser = offset within struct)
+ 0009h = Incoming Function param (with Offset = index; 0,4,8,etc.)
+ 000Ah = Type address / struc start? (with Offset = zero)
+ 000Dh = Type alias (with Offset = zero)
+
+Type definition (in chunk 94h/96h)
+(maybe lower 4bit=type, and next 4bit=usage/variant?)
+(looks same/similar as T_xxx type values in COFF files!)
+ 0000h =
+ 0001h =
+ 0002h =
+ 0003h = (16bit signed?)
+ 0004h = int (32bit signed?)
+ 0005h =
+ 0006h =
+ 0007h =
+ 0008h = (address) (32bit unsigned?) (with Definition=000Ah)
+ 0009h =
+ 000Ah =
+ 000Bh =
+ 000Ch = u_char (8bit unsigned?)
+ 000Dh = u_short,ushort (16bit unsigned?)
+ 000Eh = u_int (32bit unsigned?)
+ 000Fh = u_long (64bit unsigned?) (or rather SAME as above?)
+ 0021h = function with 0 params, and/or return="nothing"?
+ 0024h = main function with 2 params, and/or return="int"?
+ 0052h = argv (string maybe?)
+ 0038h = GsOT (huh?)
+ 00F8h = GsOT_TAG (huh?)
+ 00FCh = PACKET (huh?)
+ ?? = float,bool,string,ptr,packet,(un-)signed8/16/32/64bit,etc
+ ?? = custom type/struct (using value 000xh plus "fake" name, or so?)
+
+ __________________________________ .MAP File _________________________________
+
+PsyQ .MAP File
+The .SYM file is usually bundled with a .MAP file, which is containing a
+summary of the symbolic info as ASCII text (but without info on line numbers or
+data types). For example:
+ Start Stop Length Obj Group Section name
+ 80010000 80012D5B 00002D5C 80010000 text .rdata
+ 80012D5C 800C8417 000B56BC 80012D5C text .text
+ 800C8418 800CDAB7 000056A0 800C8418 text .data
+ 800CDAB8 800CFB63 000020AC 800CDAB8 text .sdata
+ 800CFB64 800D5C07 000060A4 800CFB64 bss .sbss
+ 800D5C08 800DD33F 00007738 800D5C08 bss .bss
+
+ Address Names alphabetically
+ 800CFE80 ACE_amount
+ 800CFB94 AIMenu
+ 800CDE5C AXIS_LENGTH
+ 8005E28C AddClippedTri
+ 8005DFEC AddVertex
+ ...
+
+ Address Names in address order
+ 00000000 _cinemax_obj
+ 00000000 _cinemax_header_org
+ 00000000 _cinemax_org
+ 00000000 _mcardx_sbss_size
+ 00000000 _mcardx_org
+ ...
+
+CDROM File Video Texture Image TIM/PXL/CLT (Sony)
+-------------------------------------------------
+
+TIM/PXL/CLT are standard formats from Sony's devkit. TIM is used by many PSX
+games.
+ .TIM contains Pixel data, and (optional) CLUT data ;-all in one file
+ .PXL contains Pixel data only ;\in two separate files
+ .CLT contains CLUT data only (if any) ;/
+
+TIM Format
+ 000h 1 File ID (always 10h=TIM)
+ 001h 1 Version (always 00h)
+ 002h 2 Reserved (always 0000h) (or 1 or 2 for Compressed TIM, see below)
+ 004h 4 Flags (bit0-2=Type; see below, bit3=HasCLUT, bit4-31=Reserved/zero)
+ ... .. Data Section for CLUT (Palette), only exists if Flags.bit3=1, HasCLUT
+ ... .. Data Section for Pixels (Bitmap/Texture)
+The Type in Flags.bit0-2 can be 0=4bpp, 1=8bpp, 2=16bpp, 3=24bpp, 4=Mixed.
+NFL Blitz 2000 (MagDemo26: B2000\DATA\ARTD_G.BIN) does additionally use Type
+5=8bit.
+The Type value value is only a hint on how to view the Pixel data (the data is
+copied to VRAM regardless of the type; 4=Mixed is meant to indicate that the
+data contains different types, eg. both 4bpp & 8bpp textures).
+Type 3=24bpp is quite rare, but does exist (eg. Colony Wars (MagDemo02:
+CWARS\GAME.RSC\DEMO.TIM).
+
+The format of the CLUT and Pixel Data Section(s) is:
+ 000h 4 Size of Data Section (Xsiz*2*Ysiz+0Ch) ;maybe rounded to 4-byte?
+ 004h 4 Destination Coord (YyyyXxxxh) ;Xpos counted in halfwords
+ 008h 4 Width+Height (YsizXsizh) ;Xsiz counted in halfwords
+ 00Ch .. VRAM Data (to be DMAed to frame buffer)
+Note: Above is usually a multiple of 4 bytes, but not always:
+Shadow Madness (MagDemo18: SHADOW\DATA\ANDY\LOADSAVE\*.TIM) contains TIM
+bitmaps with 27x27 or 39x51 halfwords; those files have odd section size & odd
+total filesize. Gran Turismo 2 (GT2.VOL\arcade\arc_other.tim\0000) also has odd
+size. Unknown if the CLUT can also have odd size (which would misalign the
+following Bitmap section).
+Bust A Groove (MagDemo18: BUSTGR_A\G_COMMON.DFS\0005) has 0x0 pixel Bitmaps
+(with CLUT data).
+
+PXL/CLT Format
+PXL/CLT is very rare. And oddly, with swapped ID values (official specs say
+11h=PXL, 12h=CLT, but the existing games do use 11h=CLT, 12h=PXL).
+Used by Granstream Saga (MagDemo10 GS\*)
+Used by Bloody Roar 1 (MagDemo06: BL\*)
+Used by Bloody Roar 2 (MagDemo22: ASC,CMN,EFT,LON,SND,ST5,STU\*)
+
+CLT Format
+ 000h 1 File ID (always 11h=CLT) (although Sony's doc says 12h)
+ 001h 1 Version (always 00h)
+ 002h 2 Reserved (always 0000h)
+ 004h 4 Flags (bit0-1=Type=2; bit2-31=Reserved/zero)
+ ... .. Data Section for CLUT (Palette)
+The .CLT Type should be always 2 (meant to indicate 16bit CLUT entries).
+
+PXL Format
+ 000h 1 File ID (always 12h=PXL) (although Sony's doc says 11h)
+ 001h 1 Version (always 00h)
+ 002h 2 Reserved (always 0000h)
+ 004h 4 Flags (bit0-?=Type; see below, bit?-31=Reserved/zero)
+ ... .. Data Section for Pixels (Bitmap/Texture)
+This does probably support the same 5 types as in .TIMs (though official Sony
+docs claim the .PXL type to be only 1bit wide, but netherless claim that PXL
+can be 4bpp, 8bpp, or 16bpp).
+
+ _______________________________ Compressed TIM _______________________________
+
+Compressed TIMs
+Ape Escape (Sony 1999) is using a customized TIM format with 4bpp compression:
+--> CDROM File Compression TIM-RLE4/RLE8
+Other than that, TIMs can be compressed via generic compression functions (like
+LZSS, GZIP), or via bitmap dedicated compression formats (like BS, JPG, GIF).
+
+ ______________________________ Malformed Files _______________________________
+
+Malformed TIMs in BIGFILE.DAT
+ Used by Legacy of Kain: Soul Reaver (eg. BIGFILE.DAT\folder04h\file13h)
+ Used by Gex - Enter the Gecko (eg. BIGFILE.DAT\file0Fh\LZcompressed)
+Malformed TIMs contain texture data preceeded by a dummy 14h-byte TIM header
+with following constant values:
+ 10 00 00 00 02 00 00 00 04 00 08 00 00 02 00 00 00 02 00 02 ;<-- this
+ 10 00 00 00 02 00 00 00 04 00 08 00 00 00 00 00 00 02 00 02 ;<-- or this
+The malformed entries include:
+ [04h]=Type should indicated the color depth, but it's always 02h=16bpp.
+ [08h]=Width*2*Height+0Ch should be 8000Ch, but malformed is 80004h.
+ Total filesize should be 80014h, but Gecko files are often MUCH smaller.
+Also, destination yloc should be 0..1FFh, but PSX "Lemmings & Oh No! More
+Lemmings" (FILES\GFX\*.TIM) has yloc=200h (that game also has vandalized .BMP
+headers with 2-byte alignment padding after ID "BM", whilst pretending that
+those extra bytes aren't there in data offset and total size entries).
+
+Oversized TIMs
+ Used by Pong (MagDemo24: LES02020\*\*.TIM)
+Has 200x200h pix, but section size (and filesize) are +2 bigger than that:
+ 10 00 00 00 02 00 00 00 0E 00 08 00 C0 01 00 00 00 02 00 02 ;Pong *.TIM
+ 10 00 00 00 02 00 00 00 0E 00 07 00 00 02 00 00 C0 01 00 02 ;Pong WORLD.TIM
+ 10 00 00 00 02 00 00 00 0E 80 03 00 00 02 00 01 C0 01 00 01 ;Pong ZONE*.TIM
+
+Miscomputed Section Size
+NBA Basketball 2000 (MagDemo28: FOXBB\TIM\*.TIM) has TIMs with section size
+"0Ch+Xsiz*Ysiz" instead of "0Ch+Xsiz*2*Ysiz".
+
+NonTIMs in Bloody Roar 1 and 2
+ Bloody Roar 1 (CMN\INIT.DAT\000Eh)
+ Bloody Roar 2 (CMN\SE00.DAT, CMD\SEL00.DAT\0030h and CMN\VS\VS.DAT\0000h)
+This looks somehow TIM-inspired, but has ID=13h.
+ 13 00 00 00 02 00 00 00 0C 20 00 00 00 00 F8 01 00 01 10 00 ;Bloody Roar 1
+ 13 00 00 00 02 00 00 00 0C 20 00 00 00 00 00 00 00 01 10 00 ;Bloody Roar 2
+
+Other uncommon/malformed TIM variants
+And, Heart of Darkness has a TIM with Size entry set to Xsiz*2*Ysiz+0Eh
+(instead of +0Ch) (that malformed TIM is found inside of the RNC compressed
+IMAGES\US.TIM file).
+Also, NFL Gameday '99 (MagDemo17: GAMEDAY\PHOTOS.FIL) contains a TIM cropped to
+800h-byte size (containing only the upper quarter of the photo).
+Also, not directly malformed, but uncommon: Final Fantasy IX contains 14h-byte
+0x0 pixel TIMs (eg. FF9.IMG\dir04\file0046\1B-0000\04-0001).
+Klonoa (MagDemo08: KLONOA\FILE.IDX\3\2\0..1) has 0x0pix TIM (plus palette).
+
+Malformed CLTs
+ Used by Secret of Mana, WM\WEFF\*.CLT
+ID is 10h=TIM, Flags=10101009h (should be ID=12h, Flags=02h).
+
+CDROM File Video Texture/Bitmap (Other)
+---------------------------------------
+
+Apart from Sony's TIM (and PXL/CLT) format, there are a bunch of other
+texture/bitmap formats:
+
+Compressed Bitmaps
+ .BS used by several games (and also in most .STR videos)
+ .GIF used by Lightspan Online Connection CD
+ .JPG used by Lightspan Online Connection CD
+ .BMP with RLE4 used by Lightspan Online Connection CD (MONOFONT, PROPFONT)
+ .BMP with RLE8+Delta also used by Online Connection CD (PROPFONT\ARIA6.BMP)
+ .PCX with RLE used by Jampack Vol. 1 (MDK\CD.HED\*.pcx)
+
+Uncompressed Bitmaps
+ .BMP
+ .BMP used by Mat Hoffman's Pro BMX (MagDemo39: BMX\BMXCD.HED\*)
+ .BMP used by Mat Hoffman's Pro BMX (MagDemo48: MHPB\BMXCD.HED\*)
+ .BMP used by Thrasher: Skate and Destroy (MagDemo27: SKATE\ASSETS\*.ZAL)
+ .BMP used by Dave Mirra Freestyle BMX (MagDemo36,46: BMX\ASSETS\*.ZAL)
+ .VRM .IMG .TEX .TIM .RAW .256 .COL .4B .15B .R16 .TPG - raw VRAM data
+ "SC" memory card icons
+
+Targa TGA and Paintbrush PCX
+--> CDROM File Video Texture/Bitmap (TGA)
+--> CDROM File Video Texture/Bitmap (PCX)
+
+PSI bitmap - Power Spike (MagDemo43: POWER\GAME.IDX\*.BIZ\*.PSI)
+ 000h 10h Name 1 ("FILENAME.BMP", zeropadded)
+ 010h 10h Name 2 ("FILENAME.PSI", zeropadded)
+ 020h 4 Bits per pixel (usually 4, 8, or 16)
+ 024h 2 Bitmap VRAM Dest.X ?
+ 026h 2 Bitmap VRAM Dest.Y ?
+ 028h 2 Bitmap Width in pixels
+ 02Ah 2 Bitmap Height in pixels
+ 02Ch 2 Palette VRAM Dest.X ? ;\zero for 16bpp
+ 02Eh 2 Palette VRAM Dest.Y ? ;/
+ 030h 2 Bitmap Width in Halfwords (PixelWidth*bpp/16)
+ 032h 2 Palette Size in Halfwords (0, 10h, 100h for 16bpp,4npp,8bpp)
+ 034h 4 Maybe Bitmap present flag (always 1)
+ 038h 4 Maybe Palette present flag (0=16bpp, 1=4bpp/8bpp)
+ 03Ch .. Bitmap pixels
+ ... .. Palette (if any, for 4bpp: 16x16bit, for 8bpp: 256x16bit)
+
+JumpStart Wildlife Safari Field Trip (MagDemo52: DEMO\DATA.DAT\*.DAT+*.PSX)
+This game does use two different (but nearly identical) bitmap formats (with
+either palette or bitmap data stored first).
+ 000h 4 Total Filesize (Width*Height+20Ch)
+ 004h 2 Bitmap Width
+ 006h 2 Bitmap Height
+ 008h 4 Unknown, always 1 (maybe 1=8bpp?)
+ In .DAT files (512x192 or 256x64 pix), palette first:
+ 00Ch 200h Palette data
+ 20Ch .. Bitmap data
+ In .PSX files (64x64 pix), bitmap first:
+ 00Ch .. Bitmap data
+ ... 200h Palette data
+To detect the "palette first" format, check for these conditions(s):
+ Filename extension is ".DAT"
+ Bitmap Width<>Height (non-square)
+ [00Ch..20Bh] has AllMSBs>=80h, and SomeLSBs<80h
+Note: The bitmaps are vertically mirrored (starting with bottom-most scanline).
+
+WxH Bitmap (Width*Height)
+Used by Alone in the Dark The New Nightmare (FAT.BIN\BOOK,DOC,INTRO,MENU\*)
+Used by Rayman (RAY\JUN,MON,MUS\*) (but seems to contain map data, not pixels)
+ 000h 2 Width (W) ;\usually 320x240 (or 512x240 or 80x13)
+ 002h 2 Height (H) ;/
+ 004h .. Bitmap 16bpp (W*H*2 bytes)
+
+RAWP Bitmap
+Used by Championship Motocross (MagDemo25: SMX\RESHAD.BIN\*) ("RAWP")
+ 000h 4 ID "RAWP" (this variant has BIG-ENDIAN width/height!)
+ 004h 2 Width (usually 280h=640pix or 140h=320pix) (big-endian!!!)
+ 006h 2 Height (usually 1E0h=480pix or F0h=240pix) (big-endian!!!)
+ 008h .. Bitmap data, 16bpp (width*height*2 bytes)
+
+XYWH Bitmap/Palette (X,Y,Width*Height) (.BIT and .CLT)
+Used by CART World Series (MagDemo04: CART\*.BIT and *.BIN\*)
+Used by NFL Gameday '98 (MagDemo04: GAMEDAY\BUILD\GRBA.FIL\*)
+Used by NFL Gameday '99 (MagDemo17: GAMEDAY\*.BIT and *.FIL\*)
+Used by NFL Gameday 2000 (MagDemo27: GAMEDAY\*.BIT)
+Used by NCAA Gamebreaker '98 (MagDemo05: GBREAKER\*.BIT and UFLA.BIN\*)
+Used by NCAA Gamebreaker 2000 (MagDemo27: GBREAKER\*.BIT and *.FIL\*)
+Used by Twisted Metal 4 (MagDemo30: TM4DATA\*.MR,*.IMG\*.bit,*.clt)
+ 000h 2 VRAM.X (X) (0..3FFh)
+ 002h 2 VRAM.X (Y) (0..1FFh)
+ 004h 2 Width in halfwords (W) (1..400h)
+ 006h 2 Height (H) (1..200h)
+ 008h .. Bitmap or Palette data (W*H*2 bytes)
+
+Doom (PSXDOOM\ABIN\PSXDOOM.WAD\*\*)
+ 000h 2 Hotspot X (signed) (usually 0)
+ 002h 2 Hotspot Y (signed) (usually 0)
+ 004h 2 Width in bytes
+ 006h 2 Height
+ 008h .. Bitmap 8bpp (Width*Height bytes)
+Most files have Hotspot X=0,Y=0, WAD\LOADING has X=FF80h,Y=FF8Ah, and WAD\S\*
+has X=0..Width, Y=0..Height+1Ah (eg. S\BKEY*, S\BFG*, S\PISFA0 have large Y).
+The files do not contain any palette info... maybe 2800h-byte PLAYPAL does
+contain the palette(s)?
+
+Lemmings & Oh No! More Lemmings (FILES\GFX\*.BOB, FILES\SMLMAPS\*.BOB)
+ 000h 2 Width
+ 002h 2 Height
+ 004h 100h*3 Palette 24bit RGB888
+ 304h .. Bitmap 8bpp (Width*Height bytes)
+ .. (1700h) Unknown (only in SMLMAPS\*.BOB, not in GFX\*.BOB)
+Apart from .BOB, the FILES\GFX folder also has vandalized .BMP (with ID
+"BM",00h,00h) and corrupted .TIM (with VRAM.Y=200h).
+
+One (DIRFILE.BIN\*.VCF)
+ 000h 4 Unknown (always 1)
+ 004h 4 Unknown (always 8)
+ 008h 4 Unknown (always 2) (maybe 2=16bpp?)
+ 00Ch 4 Width in pixels (3Ah, 140h, or 280h)
+ 010h 4 Height (3Ah, or F0h)
+ 014h .. Bitmap 16bpp (Width*Height*2 bytes)
+
+One (DIRFILE.BIN\*.VCK and DIRFILE.BIN\w*\sect*.bin\TEXTURE 001)
+ 000h 2 Number if Files (N)
+ 002h 2 Number of VRAM.Slots (less or equal than Number of Files)
+ 004h 4 ID "BLK0"
+ 008h N*10h File List
+ ... .. 1st File Bitmap
+ ... .. 1st File Palette (20h/200h/0 bytes for 4bpp/8bpp/16bpp)
+ ... .. 2nd File Bitmap
+ ... .. 2nd File Palette (only if PaletteID=FileNo=1)
+ ... .. 3rd File Bitmap
+ ... .. 3rd File Palette (only if PaletteID=FileNo=2)
+ ... .. etc.
+File List entries:
+ 000h 2 VRAM.X in halfwords (0..1Fh, +bit15=Blank) ;\within current
+ 002h 2 VRAM.Y (0..3Fh) ;/VRAM.Slot
+ 004h 2 Width in pixels (max 80h/40h/20h for 4bpp/8bpp/16bpp)
+ 006h 2 Height (max 40h)
+ 008h 2 VRAM.Slot (0,1,2,3,...,NumSlots-1)
+ 00Ah 2 Unknown (0,1,2,4 in *.vck, 4 in sect*.bin)
+ 00Ch 2 Color Depth (0=4bpp, 1=8bpp, 2=16bpp)
+ 00Eh 2 Palette ID (0..FileNo-1=Old, FileNo=New, FFFFh=None/16bpp)
+ NumFiles-1, or ID of already used palette)
+Note: VRAM.Slots are 20h*40h halfwords.
+Bitmaps can either have newly defined palettes (when PaletteID=FileNo), or
+re-use previously defined "old" palettes (when PaletteID<FileNo).
+The Blank flag allows to define a blank region (for whatever purpose), the file
+doesn't contain any bitmap/palette data for such blank regions.
+
+BMR Bitmaps
+These are 16bpp bitmaps, stored either in uncompressed .BMR files, or in
+compressed .RLE files:
+--> CDROM File Compression RLE_16
+ Apocalypse (MagDemo16: APOC\CD.HED\*.RLE and *.BMR)
+ Spider-Man 1 older version (MagDemo31: SPIDEY\CD.HED\*.RLE)
+ Spider-Man 1 newer version (MagDemo40: SPIDEY\CD.HED\*.RLE and .BMR)
+ Spider-Man 2 (MagDemo50: HARNESS\CD.HED\*.RLE)
+ Tony Hawk's Pro Skater (MagDemo22: PROSKATE\CD.HED\*.BMR)
+The width/height for known filesizes are:
+ 33408h bytes --> 512x205pix, 16bpp (Apocalypse warning.rle)
+ 3C008h bytes --> 512x240pix, 16bpp (most common)
+ 96008h bytes --> 640x480pix, 16bpp (tony hawk's pro skater)
+Most of the older BMR files (in Apocalypse) have valid 8-byte headers:
+ 000h 2 Unknown (FFA0h) (ID for files with valid headers?)
+ 002h 2 Dest.Y (usually 0) (11h=(240-205)/2 in Apocalypse warning.rle)
+ 004h 2 Width (usually 200h=512pix)
+ 006h 2 Height (usually F0h=240pix) (CDh=205pix in Apocalypse warning.rle)
+ 008h .. Bitmap data, 16bpp (width*height*2 bytes)
+Most or all newer BMR files (in Apocalypse "loadlogo.rle", and in all files in
+Spider-Man 1, Spider-Man-2, Tony Hawk's Pro Skater) have the 8-byte header
+replaced by unused 8-byte at end of file:
+ 000h .. Bitmap data, 16bpp (width*height*2 bytes)
+ .. 8 Unused (garbage or extra pixels, not transferred to VRAM)
+BUG: The bitmaps in all .BMR files (both with/without header) are distorted:
+The last 4-byte (rightmost 2pix) of each scanline should be actually located at
+the begin of the scanline, and the last scanline is shifted by an odd amount of
+bytes (resulting in nonsense 16bpp pixel colors); Spider-Man is actually
+displaying the bitmap in that distorted form (although it does mask off some
+glitches: one of the two bad rightmost pixels is replaced by a bad black
+leftmost pixel, and glitches in upper/lower lines aren't visible on 224-line
+NTSC screens).
+
+Croc 1 (retail: *.IMG) (retail only, not in MagDemo02 demo version)
+Croc 2 (MagDemo22: CROC2\CROCII.DIR\*.IMG)
+Disney's The Emperor's New Groove (MagDemo39: ENG\KINGDOM.DIR\*.IMG)
+Disney's Aladdin in Nasira's Rev. (MagDemo46: ALADDIN\ALADDIN.DIR\*.IMG)
+Contains raw 16bpp bitmaps, with following sizes:
+ 25800h bytes = 12C00h pixels (320x240) ;Croc 1 (retail version)
+ 3C000h bytes = 1E000h pixels (512x240)
+ 96000h bytes = 4B000h pixels (640x480)
+Note: The .IMG format is about same as .BMR files (but without the 8-byte
+header, and without distorted scanlines).
+
+Mat Hoffman's Pro BMX (MagDemo39: BMX\FE.WAD+STR\*.BIN) (Activision)
+Mat Hoffman's Pro BMX (MagDemo48: MHPB\FE.WAD+STR\*.BIN) (Shaba/Activision)
+ 000h 2 Bits per pixel (4 or 8)
+ 002h 2 Bitmap Width in pixels
+ 004h 2 Bitmap Height in pixels
+ 006h 2 Zero
+ 008h N*2 Palette (with N=(1 SHL bpp))
+ ... .. Bitmap (with Width*Height*bpp/8 bytes)
+ ... (..) Zeropadding to 4-byte boundary (old version only)
+The trailing alignment padding exists only in old demo version (eg. size of
+78x49x8bpp "coreypp.bin" is old=10F8h, new=10F6h).
+
+E.T. Interplanetary Mission (MagDemo54: MEGA\MEGA.CSH\*)
+ 000h 2 Type (0=4bpp, 1=8bpp, 2=16bpp)
+ 002h 2 Unknown (usually 0000h, or sometimes CCCCh)
+ 004h 2 Bitmap Width in pixels
+ 006h 2 Bitmap Height in pixels
+ 008h 200h Palette (always 200h-byte, even for 4bpp or 16bpp)
+ 208h .. Bitmap (Width*Height*bpp/8 bytes)
+Palette is 00h-or-CCh-padded when 4bpp, or CCh-filled when 16bpp.
+Note: Some files contain two or more such bitmaps (of same or different sizes)
+badged together.
+
+EA Sports: Madden NFL '98 (MagDemo02: TIBURON\*.DAT\*)
+EA Sports: Madden NFL 2000 (MagDemo27: MADN00\*.DAT\*)
+EA Sports: Madden NFL 2001 (MagDemo39: MADN01\*.DAT\*)
+This format is used in various EA Sports Madden .DAT archives, it contains
+standard TIMs with extra Headers/Footers.
+ 000h 4 Offset to TIM (1Ch) (Hdr size) (1Ch) ;\
+ 004h 4 Offset to Footer (Hdr+TIM size)(123Ch,1A3Ch,1830h) ;
+ 008h 2 Bitmap Width in pixels (40h or 60h or 30h) ;
+ 00Ah 2 Bitmap Height in pixels (40h) ;
+ 00Ch 4 Unknown, always 01h (01h) ; Header
+ 010h 4 Unknown, always 23h (23h) ; 1Ch bytes
+ 014h 2 Unknown, always 0101h (101h) ;
+ 016h 1 Bitmap Width in pixels (40h or 60h or 30h) ;
+ 017h 1 Bitmap Height in pixels (40h) ;
+ 018h 4 Unknown, always 00h (0) ;/
+ 01Ch .. TIM (Texture, can be 4bpp, 8bpp, 16bpp) ;-TIM
+ ... 4 Unknown, always C0000222h (C0000222h) ;\
+ ... 2 Unknown, always 0001h (0001h) ;
+ ... 1 Bitmap Width in pixels (40h or 60h or 30h) ; Footer
+ ... 1 Bitmap Height in pixels (40h) ; 12h bytes
+ ... 4 Unknown, always 78000000h (78000000h) ;
+ ... 6 Unknown (0,0,80h,0,0,0) ;/
+Purpose is unknown; the 8bit Width/Height entries might be TexCoords.
+The PORTRAITS.DAT archives are a special case:
+ Madden NFL '98 (MagDemo02: TIBURON\PORTRAIT.DAT) (48x64, 16bpp)
+ Madden NFL 2000 (MagDemo27: MADN00\PORTRAIT.DAT) (96x64, 8bpp plus palette)
+ Madden NFL 2001 (MagDemo39: MADN01\PORTRAIT.DAT) (64x64, 8bpp plus palette)
+Those PORTRAITS.DAT don't have any archive header, instead they do contain
+several images in the above format, each one zeropadded to 2000h-byte size.
+
+989 Sports: NHL Faceoff '99 (MagDemo17: FO99\*.KGB\*.TEX)
+989 Sports: NHL Faceoff 2000 (MagDemo28: FO2000\*.TEX)
+989 Sports: NCAA Final Four 2000 (MagDemo30: FF00\*.TEX)
+ 000h 0Ch ID "TEX PSX ",01h,00h,00h,00h ;used in 989 Sports games
+ 00Ch 4 Number of Textures
+ 010h 4 Total Filesize
+ 014h 4 Common Palette Size (0=200h, 1=None, 2=20h)
+ 018h (..) Common Palette, if any (0,20h,200h bytes)
+ ... .. Texture(s)
+ Texture format:
+ 000h 10h Filename (eg. "light1", max 16 chars, zeropadded if shorter)
+ 010h 4 Width in pixels (eg. 40h)
+ 014h 4 Height (eg. 20h or 40h)
+ 018h 4 Unknown (always 0)
+ 01Ch 4 Number of Colors (eg. 10h, 20h or 100h)
+ 020h .. Bitmap (4bpp when NumColors<=10h, 8bpp when NumColors>10h)
+ ... (..) Palette (NumColors*2 bytes, only present if Common Palette=None)
+The .TEX files may be in ISO folders, KGB archives, DOTLESS archives. And, some
+are stored in headerless .DAT/.CAT archives (which start with ID "TEX PSX ",
+but seem to have further files appended thereafter).
+
+Electronic Arts .PSH (SHPP)
+FIFA - Road to World Cup 98 (with chunk C0h/C1h = RefPack compression)
+NCAA March Madness 2000 (MagDemo32: MM2K\*.PSH)
+Need for Speed 3 Hot Pursuit (*.PSH, ZLOAD*.QPS\RefPack.PSH)
+ReBoot (DATA\*.PSH) (with chunk 6Bh)
+Sled Storm (MagDemo24: DEBUG,ART,ART2,ART3,SOUND\*.PSH) (with Comment, Mipmap)
+WCW Mayhem (MagDemo28: WCWDEMO\*.BIG\*.PSH) (with chunk C0h/C1h = RefPack)
+ 000h 4 ID "SHPP"
+ 004h 4 Total Filesize (or Filesize-0Ch, eg. FIFA'98 ZLEG*.PSH)
+ 008h 4 Number of Textures (N)
+ 00Ch 4 ID "GIMX"
+ 010h N*8 File List
+ ... .. Data (each File contains a Bitmap chunk, and Palette chunk, if any)
+ File List entries:
+ 000h 4 Name (ascii) (Mipmaps use the same name for each mipmap level)
+ 004h 4 Offset from begin of archive to first Chunk of file
+ Caution: Most PSH files do have the above offsets sorted in increasing order,
+ but some have UNSORTED offsets, eg. Sled Storm (MagDemo24: ART3\LOAD1.PSH),
+ so one cannot easily compute sizes as NextOffset-CurrOffset.
+ Note: Mipmap textures consist of two files with same name and different
+ resolution, eg. in Sled Storm (MagDemo24: ART\WORLD0x.PSH)
+ Bitmap Chunk:
+ 000h 1 Chunk Type (40h=PSX/4bpp, 41h=PSX/8bpp, 42h=PSX/16bpp)
+ 001h 3 Offset from current chunk to next chunk (000000h=None)
+ 004h 2 Bitmap Width in pixels (can be odd, pad lines to 2-byte boundary)
+ 006h 2 Bitmap Height
+ 008h 2 Center X (whatever that is)
+ 00Ah 2 Center Y (whatever that is)
+ 00Ch 2 Position X (whatever that is, plus bit12-15=flags?)
+ 00Eh 2 Position Y (whatever that is, plus bit12-15=flags?)
+ 010h .. Bitmap data (each scanline is padded to 2-byte boundary)
+ ... .. Padding to 8-byte boundary
+ Compressed Bitmap Chunk:
+ 000h 1 Chunk Type (C0h=PSX/4bpp, C1h=PSX/8bpp, and probably C2h=PSX/16bpp)
+ 001h 0Fh Same as in Chunk 40h/41h/42h (see there)
+ 010h .. Compressed Bitmap data (usually/always with Method=10FBh)
+ ... .. Padding to 8-byte boundary
+ Palette Chunk (if any) (only for 4bpp/8bpp bitmaps, not for 16bpp):
+ 000h 1 Chunk Type (23h=PSX/Palette)
+ 001h 3 Offset from current chunk to next chunk (000000h=None)
+ 004h 2 Palette Width in halfwords (10h or 100h)
+ 006h 2 Palette Height (1)
+ 008h 2 Unknown (usually same as Width) (or 80D0h or 9240h)
+ 00Ah 2 Unknown (usually 0000h) (or 0001h or 0002h)
+ 00Ch 2 Unknown (usually 0000h)
+ 00Eh 2 Unknown (usually 00F0h)
+ 010h .. Palette data (16bit per color)
+ Note: The odd 80D0h,0001h values occur in Sled Storm ART\WORKD00.PSH\TBR1)
+ Unknown Chunk (eg. ReBoot (DATA\AREA15.PSH\sp*))
+ 000h 1 Chunk Type (6Bh)
+ 001h 3 Offset from current chunk to next chunk (000000h=None)
+ 004h 8 Unknown (2C,00,00,3C,03,00,00,00)
+ 00Ch - For whatever reason, there is no 8-byte padding here
+ Comment Chunk (eg. Sled Storm (MagDemo24: ART\WORLD0x.PSH))
+ 000h 1 Chunk Type (6Fh=PSX/Comment)
+ 001h 3 Offset from current chunk to next chunk (000000h=None)
+ 004h .. Comment ("Saved in Photoshop Plugin made by PEE00751@...",00h)
+ ... .. Zeropadding to 8-byte boundary
+ Unknown Chunk (eg. Sled Storm (MagDemo24: ART\WORLD09.PSH\ADAA))
+ 000h 1 Chunk Type (7Ch)
+ 001h 3 Offset from current chunk to next chunk (000000h=None)
+ 004h 2Ch Unknown (reportedly Hot spot / Pix region, but differs on PSX?)
+The whole .PSH file or the bitmap chunks can be compressed:
+--> CDROM File Compression EA Methods
+Variants of the .PSH format are also used on PC, PS2, PSP, XBOX (with other
+Chunk Types for other texture/palette formats, and for optional extra data).
+For details, see: http://wiki.xentax.com/index.php/EA_SSH_FSH_Image
+
+Destruction Derby Raw (MagDemo35: DDRAW\*.PCK,*.FNT,*.SPR)
+This format can contain one single Bitmap, or a font with several small
+character bitmaps.
+ 000h 2 ID "BC" ;\
+ 002h 1 Color Depth (1=4bpp, 2=8bpp, 4=16bpp) ; Header
+ 003h 1 Type (40h=Bitmap, C0h=Font) ;/
+ ... (2) Palette Unknown (0 or 1) ;\only if Bitmap
+ ... (2) Palette Unknown (1) ; 4bpp or 8bpp
+ ... (..) Palette data (20h or 200h bytes for 4bpp/8bpp) ;/
+ ... 2 Bitmap Number of Bitmaps-1 (N-1) ;\
+ ... 2 Bitmap Width in pixels ;
+ ... 2 Bitmap Height in pixels ; Bitmap(s)
+ ... N*1 Bitmap Tilenumbers (eg. "ABCDEFG..." for Fonts);
+ ... N*1 Bitmap Proportional Font widths? (0xh or FFh) ;
+ ... N*BMP Bitmap(s) for all characters ;/
+ ... (20h) Palette Data (20h bytes for 4bpp) ;-only if Font/4bpp
+All bitmap scanlines are padded to 2-byte boundary, eg. needed for:
+ INGAME1\BOWL2.PTH\SPRITES.PTH\ST.SPR 30x10x4bpp: 15 --> 16 bytes/line
+ INGAME1\BOWL2.PTH\SPRITES.PTH\STOPW.SPR 75x40x4bpp: 37.5 --> 38 bytes/line
+The BC files are usually compressed (either in PCK file, or in the compressed
+DAT portion of a PTH+DAT archive).
+
+Cool Boarders 2 (MagDemo02: CB2\DATA*\*.FBD)
+ 000h 2 ID ("FB") ;\File Header
+ 002h 2 Always 1 (version? 4bpp? num entries?) ;/
+ 004h 2 Palette VRAM Dest X (eg. 300h) ;\
+ 006h 2 Palette VRAM Dest Y (eg. 1CCh,1EDh,1FFh) ; Palette Header
+ 008h 2 Palette Width in halfwords (eg. 100h) ; (all zero when unused)
+ 00Ah 2 Palette Height (eg. 1 or 0Dh) ;/
+ 00Ch 2 Bitmap VRAM Dest X (eg. 140h or 200h) ;\
+ 00Eh 2 Bitmap VRAM Dest Y (eg. 0 or 100h) ; Bitmap Header
+ 010h 2 Bitmap Width in halfwords ;
+ 012h 2 Bitmap Height ;/
+ ... .. Palette Data (if any) ;-Palette Data
+ ... .. Bitmap Data ;-Bitmap Data
+The bitmap data seems to be 4bpp and/or 8bpp, but it's hard to know the correct
+palette (some files have more than 16 or 256 palette colors, or don't have any
+palette at all).
+
+CDROM File Video Texture/Bitmap (TGA)
+-------------------------------------
+
+Targa TGA
+ 000h 1 Image ID Size (00h..FFh, usually 0=None) ;0
+ 001h 1 Palette Present Flag (0=None, 1=Present) ;0 iv=1
+ 002h 1 Data Type code (0,1,2,3,9,10,11,32,33) ;NEBULA=2 iv=1
+ 003h 2 Palette First Color (usually 0) ;0 iv=0
+ 005h 2 Palette Number of Colors (usually 100h) ;0 iv=100h
+ 007h 1 Palette Bits per Color (16,24,32, usually 24) ;0 iv=18h
+ 008h 2 Bitmap X origin (usually 0) ;0
+ 00Ah 2 Bitmap Y origin (usually 0) ;0
+ 00Ch 2 Bitmap Width ;NEBULA=20h LOGO=142h
+ 00Eh 2 Bitmap Height ;NEBULA=20h
+ 010h 1 Bitmap Bits per Pixel (8,16,24,32 exist?) ;NEBULA=18h iv=8
+ 011h 1 Image Descriptor (usually 0) ;0
+ 012h .. Image ID Data (if any, len=[00h], usually 0=None)
+ ... .. Palette
+ ... .. Bitmap
+ ... 1Ah Footer (8x00h, "TRUEVISION-XFILE.", 00h) (not present in iview)
+Data Type [02h]:
+ 00h = No image data included ;-Unknown purpose
+ 01h = Color-mapped image ;\
+ 02h = RGB image ; Uncompressed
+ 03h = Black and white image ;/
+ 09h = Color-mapped image ;\Runlength
+ 0Ah = RGB image ;/
+ 0Bh = Black and white image ;-Unknown compression method
+ 20h = Color-mapped image ;-Huffman+Delta+Runlength
+ 21h = Color-mapped image ;-Huffman+Delta+Runlength+FourPassQuadTree
+The official specs do list the above 9 types, but do describe only 4 types in
+detail (type 01h,02h,09h,0Ah).
+ Type 01h and 09h lack details on supported bits per pixel (8bpp with 100h
+ colors does exist; unknown if less (or more) than 8bpp are supported,
+ and if so, in which bit order.
+ Type 02h and 0Ah are more or less well documented.
+ Type 03h has unknown bit-order, also unknown if/how it differs from type
+ 01h with 1bpp.
+ Type 0Bh, 20h, 21h lack any details on the compression method.
+TGA's are used by a couple of PSX games/demos (all uncompressed):
+ 16bpp: Tomb Raider 2 (MagDemo01: TOMBRAID\*.RAW)
+ 24bpp: Tomb Raider 2 (MagDemo05: TOMB2\*.TGA)
+ 24bpp: Colony Wars Venegance (MagDemo14: CWV\GAME.RSC\NEBULA*.TGA, *SKY.TGA)
+ 24bpp: Colony Wars Red Sun (MagDemo31: CWREDSUN\GAME.RSC\000A\*)
+ 16bpp: Colony Wars Venegance (MagDemo14: CWV\GAME.RSC\LOGO.DAT)
+ 16bpp: X-Men: Mutant Academy (MagDemo50: XMEN2\*)
+ 16bpp: Disney's Tarzan (MagDemo42: TARZAN\*)
+ 8bpp+Wrong8bitAttr: SnoCross Championship Racing (MagDemo37: SNOCROSS\*.TGA)
+ 16bpp+WrongYflip: SnoCross Championship Racing (MagDemo37: SNOCROSS\*.TGA)
+For whatever reason, TGA is still in use on newer consoles:
+ 32bpp: 3DS AR Games (RomFS:\i_ar\tex\hm*.lz77
+
+CDROM File Video Texture/Bitmap (PCX)
+-------------------------------------
+
+PC Paintbrush .PCX files (ZSoft)
+Default extension is .PCX (some tools did use .PCX for the "main" image, and
+.PCC for smaller snippets that were clipped/cropped/copied from from a large
+image).
+ 000h 1 File ID (always 0Ah=PCX/ZSoft)
+ 001h 1 Version (0,2,3,4,5)
+ 002h 1 Compression (always 01h=RLE) (or inofficial: 00h=Uncompressed)
+ 003h 1 Bits per Pixel (per Plane) (1, 2, 4, or 8)
+ 004h 2 Window X1 ;\
+ 006h 2 Window Y1 ; Width = X2+1-X1
+ 008h 2 Window X2 ; Height = Y2+1-Y1
+ 00Ah 2 Window Y2 ;/
+ 00Ch 2 Horizontal Resolution in DPI ;\often square, but can be also zero,
+ 00Eh 2 Vertical Resolution in DPI ;/or screen size, or other values
+ 010h 30h EGA/VGA Palette (16 colors, 3-byte per color = R,G,B) (or garbage)
+ 010h 1 CGA: Bit7-4=Background Color (supposedly IRGB1111 ?)
+ 013h 1 CGA: Bit7:0=Color,1=Mono,Bit6:0=Yellow,1=White,Bit5:0=Dim,1=Bright
+ 014h 1 Paintbrush IV: New CGA Color1 Green ;\weird new way to encode CGA
+ 015h 1 Paintbrush IV: New CGA Color1 Red ;/palette in these two bytes
+ 040h 1 Reserved (00h) (but is 96h in animals.pcx)
+ 041h 1 Number of color planes (1=Palette, 3=RGB, or 4=RGBI)
+ 042h 2 Bytes per Line (per plane) (must be N*2) (=(Width*Bits+15)/16*2)
+ 044h 2 PaletteInfo? (0000h/xxxxh=Normal, 0001h=Color/BW, 0002h=Grayscale)
+ 046h 2 Horizontal screen size in pixels ;\New fields, found only
+ 048h 2 Vertical screen size in pixels ;/in Paintbrush IV/IV Plus
+ 04Ah 36h Reserved (zerofilled) (or garbage in older files, custom in MGS)
+ 080h .. Bitmap data (RLE compressed)
+ ... 1 VGA Palette ID (0Ch=256 colors) ;\when 8bpp
+ .. 300h VGA Palette (256 colors, 3-byte per color = R,G,B) ;/
+Decoding PCX files is quite a hardcore exercise due to a vast amount of
+versions, revisions, corner cases, incomplete & bugged specifications, and
+inofficial third-party glitches.
+
+PCX Versions
+ 00h = Version 2.5 whatever ancient stuff
+ 02h = Version 2.8 with custom 16-color palette
+ 03h = Version 2.8 without palette (uses fixed CGA/EGA palette)
+ 04h = Version ?.? without palette (uses fixed CGA/EGA palette)
+ 05h = Version 3.0 with custom 16-color or 256-color palette or truecolor
+NOTE: Version[01h]=05h with PaletteInfo[44h]=0001h..0002h is Paintbrush IV?
+
+Known PCX Color Depths
+ planes=1, bits=1 P1 ;1bit, HGC 2 color (iview and paint shop pro 2)
+ planes=1, bits=2 P2 ;2bit, CGA 4 color (with old/new palette info)
+ planes=3, bits=1 RGB111 ;3bit, EGA 8 color (official samples) ;\version
+ planes=4, bits=1 IRGB1111 ;4bit, EGA 16 color (paint shop pro 2) ;/03h..04h
+ planes=1, bits=4 P4 ;4bit, BMP 16 color (iview)
+ planes=1, bits=8 P8 ;8bit, VGA 256 color palette
+ planes=1, bits=8 I8 ;8bit, VGA 256 level grayscale (gmarbles.pcx)
+ planes=3, bits=8 BGR888 ;24bit, truecolor (this is official 24bit format)
+ ;planes=1, bits=24 BGR888 ? ;24bit, reportedly exists? poor compression
+ ;planes=4, bits=4 ABGR4444 ;16bit, wikipedia-myth? unlikely to exist
+ ;planes=4, bits=8 ABGR8888 ;32bit, truecolor+alpha (used in abydos.dcx\*)
+
+Width and Height
+These are normally calculated as so:
+ Width = X2+1-X1 ;width for normal files
+ Height = Y2+1-Y1 ;height for normal files
+However, a few PCX files do accidentally want them to be calculated as so:
+ Width = X2-X1 ;width for bugged files
+ Height = Y2-Y1 ;height for bugged files
+Files with bugged width can be (sometimes) detected as so:
+ (Width*Bits+15)/16*2) > BytesPerLine
+Files with bugged height can be detected during decompression:
+ BeginOfLastScanline >= Filesize (or Filesize-301h for files with palette)
+Bugged sample files are SAMPLE.DCX, marbles.pcx and gmarbles.pcx. RLE
+decompression may crash when not taking care of such files.
+
+Color Planes and Palettes
+The official ZSoft PCX specs are - wrongly - describing planes as:
+ plane0 = red ;\
+ plane1 = green ; this is WRONG, NONSENSE, does NOT exist
+ plane2 = blue ;
+ plane3 = intensity ;/
+The 8-color and 16-color EGA images are actually using plane0,1,2,(3) as
+bit0,1,2,(3) of the EGA color number; which implies plane0=blue (ie. red/blue
+are opposite of the ZSoft document).
+The truecolor and truecolor+alpha formats have plane0..2=red,green,blue (as
+described by ZSoft), but they don't have any intensity plane (a few files are
+using plane3=alpha).
+
+Mono 2-Color Palette
+This format was intended for 640x200pix 2-color CGA graphics, it's also common
+for higher resolution FAX or print images. The general rule for these files is
+to use this colors:
+ color0=black
+ color1=white
+There are rumours that color1 could be changed to any of the 16 CGA colors
+(supposedly via [10h].bit7-4, but most older & newer 2-color files have that
+byte set to 00h, so one would end up with black-on-black).
+Some newer 2-color files contain RGB palette entries [10h]=000000h,
+[13h]=FFFFFFh (and [16h..3Fh]=00h-filled or FFh-filled).
+Iview does often display 2-color images with color1=dark green (somewhat
+mysteriously; it's doing that even for files that don't contain any CGA color
+numbers or RGB palette values that could qualify as dark green).
+
+4-Color Palettes
+This format was intended for 320x200pix 4-color CGA graphics, and the palette
+is closely bound to colors available in CGA graphics modes. Color0 is defined
+in [10h], and Color1-3 were originally defined in [13h], and later in
+[14h,15h]:
+ color0=[10h].bit7-4 ;(Color0 IRGB) ;CGA Port 3D9h.bit3-0 (usually 0=black)
+ bright=[13h].bit5 ;CGA Port 3D9h.bit4 ;\
+ palette=[13h].bit6 ;CGA Port 3D9h.bit5 ; old method
+ if [13h].bit7 then palette=2 ;CGA Port 3D8h.bit2 ;/
+ if [01h]=05h and [44h]=0001h then ;\new "smart"
+ if [14h]>200 or [15h]>200 then bright=1, else bright=0 ; method used in
+ if [14h]>[15h] then palette=0 else palette=1 :/Paintbrush IV
+ if palette=0 and bright=0 then color1..3=02h,04h,06h ;\green-red-yellow
+ if palette=0 and bright=1 then color1..3=0Ah,0Ch,0Eh ;/
+ if palette=1 and bright=0 then color1..3=03h,05h,07h ;\cyan-magenta-white
+ if palette=1 and bright=1 then color1..3=0Bh,0Dh,0Fh ;/
+ if palette=2 and bright=0 then color1..3=03h,04h,07h ;\cyan-red-white
+ if palette=2 and bright=1 then color1..3=0Bh,0Ch,0Fh ;/
+Palette=2 uses some undocumented CGA glitch, it was somewhat intended to output
+grayscale by disabling color burst on CGA hardware with analog composite
+output, but actually most or all CGA hardware is having digital 4bit IRGB
+output, which outputs cyan-red-white.
+The new "smart" method is apparently trying to detect if [13h-1Bh] contains RGB
+values with Color1=Green or Cyan, and to select the corresponding CGA palette;
+unfortunately such PCX files are merely setting [14h,15h] to match up with the
+"smart" formula, without actually storing valid RGB values in [13h-1Bh].
+
+8-Color and 16-Color, with fixed EGA Palettes (version=03h or 04h)
+These images have 3 or 4 planes. Plane0-3 correspond to bit0-3 of the EGA color
+numbers (ie. blue=plane0, green=plane1, red=plane2, and either intensity=plane3
+for 16-color, or intensity=0 for 8-color images).
+Some 8-Color sample images (with version=03h and 04h) can be found bundled with
+PC Paintbrush Plus 1.22 for Windows. A 16-color sample called WINSCR.PCX can be
+found elsewhere in internet.
+Caution 1: Official ZSoft specs are wrongly claiming plane0=red and
+plane2=blue; this is wrong (although Paint Shop Pro 2 is actually implementing
+it that way) (whilst MS Paint for Win95b can properly display them) (most other
+tools are trying to read a palette from [10h..3Fh], which is usually garbage
+filled in version=03h..04h).
+Caution 2: The standard EGA palette is used for version=03h..04h (many docs
+claim it to be used for version=03h only).
+
+16-Color, with custom EGA/VGA Palettes (version=02h or 05h)
+These can have 1 plane with 4 bits, or 4 planes with 1 bit. Header[10h..3Fh]
+contains a custom 16-color RGB palette with 3x8bit per R,G,B.
+Classic VGA hardware did only use the upper 6bit of the 8bit values.
+Classic EGA hardware did only use the upper 2bit of the 8bit values (that, only
+when having a special EGA monitor with support for more than 16 colors).
+
+256-Color VGA Palettes (version=05h)
+These have 1 plane with 8 bits. And a 256-color RGB palette with 3x8bit per
+R,G,B appended at end of file.
+The appended 256-color palette should normally exist only in 256-color images,
+some PCX tools are reportedly always appending the extra palette to all
+version=05h files (even for 2-color files).
+
+256-Level Grayscale Images (version=05h and [44h]=0002h)
+The most obvious and reliable way is to use a palette with grayscale RGB
+values. However, Paintbrush IV is explicetly implementing (or ignoring?) an
+obscure grayscale format with following settings:
+ [01h]=version=05h, and [44h]=0002h=grayscale
+That settings are used in a file called gmarbles.pcx (which does contain a
+256-color RGB palette with gray RGB values, ie. one can simply ignore the
+special settings, and display it as normal 256-color image).
+
+Default 16-color CGA/EGA Palettes
+ Color Name IRGB1111 RGB222 RGB888 Windows
+ 00h dark black 0000 000 000000 000000
+ 01h dark blue 0001 002 0000AA 000080
+ 02h dark green 0010 020 00AA00 008000
+ 03h dark cyan 0011 022 00AAAA 008080
+ 04h dark red 0100 200 AA0000 800000
+ 05h dark magenta 0101 202 AA00AA 800080
+ 06h dark yellow (brown) 0110 210!! AA5500!! 808000
+ 07h dark white (light gray) 0111 222 AAAAAA C0C0C0!!
+ 08h bright black (dark gray) 1000 111 555555 808080!!
+ 09h bright blue 1001 113 5555FF 0000FF
+ 0Ah bright green 1010 131 55FF55 00FF00
+ 0Bh bright cyan 1011 133 55FFFF 00FFFF
+ 0Ch bright red 1100 311 FF5555 FF0000
+ 0Dh bright magenta 1101 313 FF55FF FF00FF
+ 0Eh bright yellow 1110 331 FFFF55 FFFF00
+ 0Fh bright white 1111 333 FFFFFF FFFFFF
+Some notes on number of colors:
+ CGA supports 16 colors in text mode (but only max 4 colors in graphics mode).
+ EGA supports the same 16 colors as CGA in both text and graphics mode.
+ EGA-with-special-EGA-monitor supports 64 colors (but only max 16 at once).
+ VGA supports much colors (but can mimmick CGA/EGA colors, or similar colors)
+CGA is using a 4pin IRGB1111 signal for up to 16 colors in text mode (max 4
+colors in graphics mode), and CGA monitors contain some circuitry to convert
+"dark yellow" to "brown" (though cheap CGA clones may display it as "dark
+yellow").
+EGA can display CGA colors (with all 16 colors in graphics mode).
+EGA-with-special-EGA-monitor uses 6pin RGB222 signals for up to 64 colors (but
+not more than 16 colors at once).
+Windows is also using those 16 standard colors (when not having any VGA driver
+installed, and also in 256-color VGA mode, in the latter case the 16 standard
+colors are held to always available (even if different tasks are trying to
+simultanously display different images with different palettes).
+However, Windows has dropped brown, and uses non-pastelized bright colors.
+
+PCX files in PSX games
+ .PCX with RLE used by Jampack Vol. 1 (MDK\CD.HED\*.pcx)
+ .PCX with RLE used by Hot Wheels Extreme Racing (MagDemo52: US_01293\MISC\*)
+ .PCX with RLE used by Metal Gear Solid (slightly corrupted PCX files)
+
+PCX files in PSX Metal Gear Solid (MGS)
+MGS is storing some extra data at [4Ah..57h] (roughly resembling the info in
+TIM files).
+ 04Ah 2 Custom MGS ID (always 3039h)
+ 04Ch 2 Display Mode? (08h/18h=4bit, 09h/19h=8bit)
+ 04Eh 2 Bitmap X-coordinate in VRAM (reportedly "divided by 2" ???)
+ 050h 2 Bitmap Y-coordinate in VRAM
+ 052h 2 Palette X-coordinate in VRAM
+ 054h 2 Palette Y-coordinate in VRAM
+ 056h 2 Palette number of actually used colors (can be less than 16/256)
+ 058h 28h Reserved (zerofilled)
+ 080h .. Bitmap data (RLE compressed)
+ ... 1 VGA Palette ID (0Ch=256 colors) ;\when 8bpp
+ .. 300h VGA Palette (256 colors, 3-byte per color = R,G,B) ;/
+ .. .. Padding to 4-byte boundary, ie. palette isn't at filesize-301h !!!
+MGS has filesize padded to 4-byte boundary. That is causing problems for files
+with 256-color palette: The official way to find the palette is to stepback
+301h bytes from end of file, which won't work with padding. To find the MGS
+palette, one must decompress the whole bitmap, and then expect the 301h-byte
+palette to be located after the compressed data.
+As an extra oddity, MGS uses non-square ultra-high DPI values.
+
+DCX Archives
+DCX archives contain multiple PCX files (eg. multi-page FAX documents). The
+standard format is as so:
+ 0000h 4 ID (3ADE68B1h) (987654321 decimal)
+ 0004h 4000h File List (32bit offsets) (max 1023 files, plus 0=End of List)
+ 1004h .. File Data area (PCX files)
+However, some files have the first PCX at offset 1000h (ie. the list is only
+3FFCh bytes tall). Reportedly there are also files that start with yet smaller
+offsets (for saving space when the file list contains fewer entries).
+The PCX filesize is next-curr offset (or total-curr for last file).
+
+References
+https://www.fileformat.info/format/pcx/egff.htm
+
+CDROM File Video 2D Graphics CEL/BGD/TSQ/ANM/SDF (Sony)
+-------------------------------------------------------
+
+CEL/BGD/TSQ/ANM/SDF
+
+CEL: Cell Data (official format with 8bit header entries)
+This does merely translate Tile Numbers to VRAM Addresses and Attributes (with
+the actual VRAM bitmap data usually being stored in .TIM files).
+ 000h 1 File ID (22h)
+ 001h 1 Version (3)
+ 002h 2 Flag (bit15=WithAttr, bit14=AttrDataSize:0=8bit,1=16bit, bit13-0=0)
+ 004h 2 Number of cell data items (in cell units) (N)
+ 006h 1 Sprite Editor Display Window Width (in cell units)
+ 007h 1 Sprite Editor Display Window Height (in cell units)
+ 008h .. Cell Data[N] (64bit entries)
+ ... .. Cell Attr[N] (0bit/8bit/16bit user data? depending on Flag)
+Cell Data:
+ 0-7 Tex Coord X (8bit)
+ 8-15 Tex Coord Y (8bit)
+ 16-21 Clut X (6bit)
+ 22-30 Clut X (9bit)
+ 31 Semi-transparency enable ;-only in Version>=3
+ 32 Vertical Reversal (Y-Flip) ;\only in Version=0 and Version>=2
+ 33 Horizontal Reversal (X-Flip) ;/
+ 34-47 Unused
+ 48-52 Texture Page (5bit)
+ 53-54 Semi Transparency (0=B/2+F/2, 1=B+F, 2=B-F, 3=B+F/4)
+ 55-56 Texture page colors (0=4bit, 1=8bit, 2=15bit, 3=Reserved)
+ 57-60 Sprite Editor Color Set Number ;\
+ 61 Unused ; only in Version>=3
+ 62-63 Sprite Editor TIM Bank ;/ XXX else hardcoded?
+This is used in R-Types, CG.1\file3Dh\file00h, but [6,7] are 16bit wide! And
+there are a LOT of ZEROes appended (plus FFh-padding due to CG.1 archive size
+units).
+Used by R-Types (CG.1\file07h\file01h, size 08h*04h, with 8bit attr)
+Used by R-Types (CG.1\file07h\file03h, size 10h*08h, with 16bit attr)
+Used by R-Types (CG.1\file07h\file05h, size 04h*04h, with 16bit attr)
+Used by Tiny Tank (MagDemo23: TINYTANK\TMD05.DSK\*.CEL, size 08h*05h)
+
+CEL16: Inofficial CEL hack with 16bit entries and more extra data (R-Types)
+This is an inofficial hack used by R-Types, the game does use both the official
+CEL and inofficial CEL16 format.
+ 000h 1 File ID (22h) ;\same as in official CEL version
+ 001h 1 Version (3) ;/
+ 002h 2 Flag (...unknown meaning in this case...?) ;<-- ?
+ 004h 2 Number of cell data items (in cell units) (N)
+ 006h 2 Sprite Editor Display Window Width (in cell units) ;<-- 16bit!
+ 008h 2 Sprite Editor Display Window Height (in cell units) ;<-- 16bit!
+ 00Ah .. Cell Data[N] (64bit entries)
+ ... .. Cell Attr[N] (16bit/192bit user data, depending on Flag or so...?)
+Used by R-Types (CG.1\file12h\file00h, size 0120h*000Fh with 192bit attr)
+Used by R-Types (CG.1\file15h\file00h, size 0168h*000Fh with ? attr)
+Used by R-Types (CG.1\file1Ch\file00h, size 00D8h*000Fh with ? attr)
+
+BGD: BG Map Data (official format with 8bit header entries)
+ 000h 1 File ID (23h)
+ 001h 1 Version (0)
+ 002h 2 Flag (bit15=WithAttr, bit14=AttrDataSize:0=8bit,1=16bit, bit13-0=0)
+ 004h 1 BG Map Width (in cell units) (W)
+ 005h 1 BG Map Height (in cell units) (H)
+ 006h 1 Cell Width (in pixels)
+ 007h 1 Cell Height (in pixels)
+ 008h .. BG Map Data[W*H] (16bit cell numbers)
+ ... .. BG Map Attr[W*H] (0bit/8bit/16bit user data? depending on Flag)
+Used by R-Types (CG.1\file07h\file00h, official BGD format)
+Used by Cardinal Syn (MagDemo03,09: SYN\SONY\KROLOGO.WAD\*.BGD)
+Used by Tiny Tank (MagDemo23: TINYTANK\TMD05.DSK\*.BGD, with 8bit entries).
+
+BGD16: Inofficial BGD hack with 16bit entries (R-Types)
+This is an inofficial hack used by R-Types, the game does use both the official
+BGD and inofficial BGD16 format. Apparently invented to support bigger BG Map
+Widths for huge sidescrolling game maps.
+ 000h 1 File ID (23h) ;\same as in official BGD version
+ 001h 1 Version (0) ;/
+ 002h 2 Flag (bit15=WithAttr, bit14=AttrDataSize:0=8bit,1=16bit, bit13-0=0)
+ 004h 2 BG Map Width (in cell units) (W) ;<-- 16bit!
+ 006h 2 BG Map Height (in cell units) (H) ;<-- 16bit!
+ 008h 2 Cell Width (in pixels) ;<-- 16bit!
+ 00Ah 2 Cell Height (in pixels) ;<-- 16bit!
+ 00Ch .. BG Map Data[W*H] (16bit cell numbers)
+ ... .. BG Map Attr[W*H] (0bit/8bit/16bit user data? depending on Flag)
+ ... .. FFh-padding (in case being stored in R-Types' DOT1 archives)
+Used by R-Types (CG.1\file3Ch\file00h, inofficial BGD16 format)
+
+TSQ: Animation Time Sequence
+ 000h 1 File ID (24h)
+ 001h 1 Version (1)
+ 002h 2 Number of Sequence data entries (N)
+ 004h N*8 Sequence Data (64bit entries)
+Sequence Data:
+ 0-15 Sprite Group Number to be displayed
+ 16-23 Display Time
+ 24-27 Unused
+ 28-31 Attribute (user defined) (only in Version>=1)
+ 32-47 Hotspot X Coordinate
+ 48-63 Hotspot Y Coordinate
+There aren't any known games using .TSQ files.
+
+ANM: Animation Information
+ 000h 1 File ID (21h)
+ 001h 1 Version (3=normal) (but see below notes on older versions)
+ 002h 2 Flag (bit0-1=TPF, bit2-11=0, bit12-15=CLT)
+ 0-1 TPF PixFmt (0=4bpp, 1=8bpp, 2/3=Reserved) ;version>=2 only
+ 2-11 - Reserved (0)
+ 12-15 CLT Number of CLUT Groups, for color animation
+ 004h 2 Number of Sprites Groups
+ 006h 2 Number of Sequences (N) (can be 0=None)
+ 008h N*8 Sequence(s) (64bit per entry) ;Num=[004h]
+ ... .. Sprite Group(s) ;Num=[006h]
+ ... .. CLUT Group(s) ;Num=[002h].bit12-15
+Sequence entries:
+ 000h 2 Sprite Group Number to be displayed (range 0..AnimHdr[004h]-1)
+ 002h 1 Display Time (can be 00h or 0Ah or whatever)
+ 003h 1 Attribute (bit0-3=Unused/Zero, bit4-7=User defined) ;version>=3 only
+ 004h 2 Hotspot X Coordinate (usually 0, or maybe can be +/-NN ?)
+ 006h 2 Hotspot Y Coordinate (usually 0, or maybe can be +/-NN ?)
+Sprite Group entries:
+ Each "Group" seems to represent one animation frame.
+ Each "Group" can contain one or more sprites (aka metatiles).
+ Below stuff is "4+N*14h" bytes, that seems to repeat "AnmHeader[004h] times"
+ XXX... actually below can be "4+N*10h" or "4+N*14h" bytes
+ XXX... so, maybe maybe some entries like width/height are optional?
+ 000h 4 Number of Sprites in this Sprite Group ("sprites per metatile"?)
+ 004h 14h*N Sprite(s) (see below)
+ Sprites:
+ 000h 1 Tex Coord X (8bit)
+ 001h 1 Tex Coord Y (8bit)
+ 002h 1 Offset X from Hotspot within frame (maybe vertex x ?)
+ 003h 1 Offset Y from Hotspot within frame (maybe vertex y ?)
+ 004h 2 CBA Clut Base (bit0-5=ClutX, Bit6-14=ClutY, bit15=SemiTransp)
+ 006h 2 FLAGs (bit0-4, bit5-6, bit7-8, bit9, bit10, bit11, bit12-15)
+ 0-4 TPN Texture Page Number
+ 5-6 ABR Semi-Transparency Rate
+ 7-8 TPF Pixel depth (0=4bpp, 1=8bpp, 2=16bpp)
+ 9 - Reserved
+ 10 RSZ Scaling (0=No, 1=Scaled)
+ 11 ROT Rotation (0=No, 1=Rotated)
+ 12-15 THW Texture Width/Height div8 (0=Other custom width/height)
+ 008h (2) Texture Width "of optional size" (uh?) ;\only present if
+ 00Ah (2) Texture Height "of optional size" (uh?) ;/FLAGs.bit12-15=0 ?)
+ 00Ch 2 Angle of Rotation (in what units?)
+ 00Eh 2 Sprite Editor info (bit0-7=Zero, bit8-13=ClutNo, bit14-15=TimBank)
+ 010h 2 Scaling X (for Vertex?) (as whatever fixed point number) (eg. 1000h)
+ 012h 2 Scaling Y (for Vertex?) (as whatever fixed point number) (eg. 1000h)
+CLUT Group entries:
+ 000h 4 CLUT size in bytes (Width*Height*2+0Ch)
+ 004h 2 Clut X Coordinate
+ 006h 2 Clut Y Coordinate
+ 008h 2 Clut Width
+ 00Ah 2 Clut Height
+ 00Ch .. CLUT entries (16bit per entry, Width*Height*2 bytes)
+Note: ALICE.PAC\MENU.PAC\CON00.ANM has NumSequences=0 and NumSpriteGroups=2Dh
+(unknown if/how that is animated, maybe it has 2Dh static groups? or the groups
+are played in order 0..2Ch with display time 1 frame each?).
+Used by Alice in Cyberland (ALICE.PAC\*.ANM) (ANM v3)
+Unknown if there are any other games are using that format.
+
+SDF: Sprite Editor Project File
+This is an ASCII text file for "artist boards" with following entries:
+ TIM0 file0.tim ;\
+ TIM1 file1.pxl file1.clt ; four TIM banks (with TIM or PXL/CLT files)
+ TIM2 ; (or no filename for empty banks)
+ TIM3 ;/
+ CEL0 file0.cel ;-one CEL (with CEL, or no filename if none)
+ MAP0 file0.bgd ;\
+ MAP1 file1.bgd ; four BG MAP banks (with BGD filenames)
+ MAP2 ; (or no filename for empty banks)
+ MAP3 ;/
+ ANM0 file0.anm ;-one ANM (with ANM, or no filename if none)
+ DISPLAY n ;0-3=256/320/512/640x240, 4-7=256/320/512/640x480
+ COLOR n ;0=4bpp, 1=8bpp ;docs are unclear, is it COLORn or COLOR n?
+ ADDR0 texX texY clutX clutY numColorSets ;\
+ ADDR1 texX texY clutX clutY numColorSets ; four texture/palette offsets
+ ADDR2 texX texY clutX clutY numColorSets ; for the corresponding TIM banks
+ ADDR3 texX texY clutX clutY numColorSets ;/ (or whatever for empty banks?)
+
+CDROM File Video 3D Graphics TMD/PMD/TOD/HMD/RSD (Sony)
+-------------------------------------------------------
+
+ ____________________________________ TMD _____________________________________
+
+TMD - Modeling Data for OS Library
+ 000h 4 ID (00000041h)
+ 004h 4 Flags (bit0=FIXP, bit1-31=Reserved/zero)
+ 008h 4 Number of Objects (N) ;"integral value" uh?
+ 00Ch N*1Ch Object List (1Ch-byte per entry)
+ ... .. Data (Vertices, Normals, Primitives)
+Object List entries:
+ 000h 4 Start address of a Vertex ;\Address values depend on the
+ 004h 4 Number of Vertices ; file header's FIXP flag:
+ 008h 4 Start address of a Normal ; FIXP=0 Addr from begin of Object
+ 00Ch 4 Number of Normals ; FIXP=0 Addr from begin of TMD File
+ 010h 4 Start address of a Primitive ;
+ 014h 4 Number of Primitives ;/
+ 018h 4 Scale (signed shift value, Pos=SHL, Neg=SHR) (not used by LIBGS)
+Vertex entries (8-byte):
+ 000h 2 Vertex X (signed 16bit)
+ 002h 2 Vertex Y (signed 16bit)
+ 004h 2 Vertex Z (signed 16bit)
+ 006h 2 Unused
+Normal entries (8-byte) (if any, needed only for computing light directions):
+ 000h 2 Normal X (fixed point 1.3.12)
+ 002h 2 Normal Y (fixed point 1.3.12)
+ 004h 2 Normal Z (fixed point 1.3.12)
+ 006h 2 Unused
+Primitive entries (variable length):
+ 000h 1 Output Size/4 of the GPU command (after GTE conversion)
+ 001h 1 Input Size/4 of the Packet Data in the TMD file
+ 002h 1 Flag
+ 0 Light source calculation (0=On, 1=Off)
+ 1 Clip Back (0=Clip, 1=Don't clip) (for Polygons only)
+ 2 Shading (0=Flat, 1=Gouraud)
+ (Valid only for the polygon not textured,
+ subjected to light source calculation)
+ 3-7 Reserved (0)
+ 003h 1 Mode (20h..7Fh) (same as GP0(20h..7Fh) command value in packet)
+ 004h .. Packet Data
+Packet Data (for Polygons)
+ 000h 4 GPU Command+Color for that packet (CcBbGgRrh), see GP0(20h..3Fh)
+ ... (4) Texcoord1+Palette (ClutYyXxh) ;\
+ ... (4) Texcoord2+Texpage (PageYyXxh) ; only if Mode.bit2=1
+ ... (4) Texcoord3 (0000YyXxh) ;
+ ... (4) Texcoord4 (0000YyXxh) ;-quad only ;/
+ ... (4) Color2 (00BbGgRrh) ;\
+ ... (4) Color3 (00BbGgRrh) ; only if Flag.bit2=1
+ ... (4) Color4 (00BbGgRrh) ;-quad only ;/
+ ... (2) Normal1 (index in Normal list?) ;always, unless Flag.bit0=1
+ ... 2 Vertex1 (index in Vertex list?)
+ ... (2) Normal2 (index in Normal list?) ;-only if Mode.bit4=1
+ ... 2 Vertex2 (index in Vertex list?)
+ ... (2) Normal3 (index in Normal list?) ;-only if Mode.bit4=1
+ ... 2 Vertex3 (index in Vertex list?)
+ ... (2) Normal4 (index in Normal list?) ;\quad only ;-only if Mode.bit4=1
+ ... 2 Vertex4 (index in Vertex list?) ;/
+ ... (2) Unused zeropadding (to 4-byte boundary)
+Packet Data (for Lines)
+ 000h 4 GPU Command+Color for that packet (CcBbGgRrh), see GP0(40h,50h)
+ ... (4) Color2 (00BbGgRrh) ;-only if Mode.bit4=1
+ ... 2 Vertex1 (index in Vertex list?)
+ ... 2 Vertex2 (index in Vertex list?)
+Packet Data (for Rectangle/Sprites)
+ 000h 4 GPU Command+Color for that packet (CcBbGgRrh), see GP0(60h..7Fh)
+ ... .. Unknown, reportedy "with 3-D coordinates and the drawing
+ content is the same as a normal sprite."
+Note: Objects should usually contain Primitives and Vertices (and optionally
+Normals), however, N2O\SHIP.TMD does contain some dummy Objects with Number of
+Vertices/Normals/Primitives all set to zero.
+Used by Playstation Logo (in sector 5..11 on all PSX discs, 3278h bytes)
+Used by ...???model???... (MagDemo54: MODEL\*.BIN\*.TMD)
+Used by Alice in Cyberland (ALICE.PAC\xxx_TM*.FA\*.TMD)
+Used by Armored Core (MagDemo02: AC10DEMP\MS\MENU_TMD.T\*)
+Used by Bloody Roar 1 (MagDemo06: CMN\EFFECT.DAT\0005h)
+Used by Deception III Dark Delusion (MagDemo33: DECEPT3\K3_DAT.BIN\056A,0725\*)
+Used by Gundam Battle Assault 2 (DATA\*.PAC\*)
+Used by Hear It Now (Playstation Developer's Demo) (*.TMD and FISH.DAT).
+Used by Jersey Devil (MagDemo10: JD\*.BZZ\*)
+Used by Klonoa (MagDemo08: KLONOA\FILE.IDX\*)
+Used by Legend of Dragoon (MagDemo34: LOD\DRAGN0.BIN\16xxh)
+Used by Macross VF-X 2 (MagDemo23: VFX2\DATA01\*.TMD)
+Used by Madden NFL '98 (MagDemo02: TIBURON\MODEL01.DAT\*)
+Used by No One Can Stop Mr. Domino (MagDemo18: DATA\*, .TMD and DOT1\TMD)
+Used by O.D.T. (MagDemo17: ODT\*.LNK\*)
+Used by Parappa (MagDemo01: PARAPPA\COMPO01.INT\3\*.TMD)
+Used by Resident Evil 1 (PSX\ITEM_M1\*.DOR\0001)
+Used by Starblade Alpha (FLT\SB2.DAT\* and TEX\SB2.DAT\*)
+Used by Tiny Tank (MagDemo23: TINYTANK\TMD*.DSK\*.TMD)
+Used by WCW/nWo Thunder (MagDemo19: THUNDER\RING\*.TMD)
+Used by Witch of Salzburg (the MODELS\*.MDL\*.TMD)
+Used by Scooby Doo and the Cyber Chase (MagDemo54: MODEL\*\*)
+
+ ____________________________________ PMD _____________________________________
+
+PMD - High-Speed Modeling Data
+This is about same as TMD, with less features, intended to work fasrer.
+ 000h 4 ID (00000042h)
+ 004h 4 Offset to Primitives
+ 008h 4 Offset to Shared Vertices (or 0=None)
+ 00Ch 4 Number of Objects
+ 010h .. Objects (4+N*4 bytes each, with offsets to Primitives)
+ ... .. Primitives
+ ... .. Shared Vertices (8-bytes each, if any)
+Vertex entries (8-byte):
+ 000h 2 Vertex X (signed 16bit)
+ 002h 2 Vertex Y (signed 16bit)
+ 004h 2 Vertex Z (signed 16bit)
+ 006h 2 Unused
+Objects:
+ 000h 4 Number of Primitives
+ 004h N*4 Offsets to Primitives ... maybe relative to hdr[004h] ?
+Primitives:
+ 000h 2 Number of Packets
+ 002h 2 Type flags
+ 0 Polygon (0=Triangle, 1=Quadrilateral)
+ 1 Shading (0=Flat, 1=Gouraud) ;uh, with ONE color?
+ 2 Texture (0=Texture-On, 1=Texture-Off) ;uh, withoutTexCoord?
+ 3 Shared (0=Independent vertex, 1=Shared vertex)
+ 4 Light source calculation (0=Off, 1=On) ;uh, withoutNormal?
+ 5 Clip (0=Back clip, 1=No back clip)
+ 6-15 Reserved for system
+ 004h ... Packet(s)
+Packet entries, when Type.bit3=0 (independent vertex):
+ 000h 4 GPU Command+Color for that packet (CcBbGgRrh), see GP0(20h..7Fh)
+ 004h 8 Vertex1 (Xxxxh,Yyyyh,Zzzzh,0000h)
+ 00Ch 8 Vertex2 (Xxxxh,Yyyyh,Zzzzh,0000h)
+ 014h 8 Vertex3 (Xxxxh,Yyyyh,Zzzzh,0000h)
+ 01Ch (8) Vertex4 (Xxxxh,Yyyyh,Zzzzh,0000h) ;<-- only when Type.bit0=1 (quad)
+Packet entries, when Type.bit3=1 (shared vertex):
+ 000h 4 GPU Command+Color for that packet (CcBbGgRrh), see GP0(20h..7Fh)
+ 004h 4 Offset to Shared Vertex1 ;offsets are
+ 008h 4 Offset to Shared Vertex2 ;"from the start of a row"
+ 00Ch 4 Offset to Shared Vertex3 ;aka from "Packet+04h" ?
+ 010h (4) Offset to Shared Vertex4 ;<-- only when Type.bit0=1(quad)
+Unknown if/how Texture/Light is implemented... without TexCoords/Normals?
+Unknown if/how Gouraud is implemented... with ONE color and without Normals?
+Used only by a few games:
+ Cool Boarders 2 (MagDemo02: CB2\DATA3\*.PMD)
+ Cardinal Syn (MagDemo03,09: SYN\*\*.WAD\*.PMD) (4-byte hdr plus PMD file)
+ Sesame Streets Sports (MagDemo52: SSS\LV*\*MRG\*) (4-byte hdr plus PMD file)
+Unknown if/which other games are using the PMD format.
+
+ ____________________________________ TOD _____________________________________
+
+TOD - Animation Data
+ 000h 1 ID (50h)
+ 001h 1 Version (0)
+ 002h 2 Resolution (time per frame in 60Hz units, can be 0) (60Hz on PAL?)
+ 004h 4 Number of Frames
+ 008h .. Frame1
+ ... .. Frame2
+ ... .. Frame3
+ ... .. etc.
+Frames:
+ 000h 2 Frame Size in words (ie. size/4)
+ 002h 2 Number of Packets (can be 0=None, ie. do nothing this frame)
+ 004h 4 Frame Number (increasing 0,1,2,3,..)
+ 008h ... Packet(s)
+Packet:
+ 000h 2 Object ID
+ 002h 1 Type/Flag (bit0-3=Type, bit4-7=Flags)
+ 003h 1 Packet Size ("in words (4 bytes)")
+ 004h ... Packet Data
+XXX... in Sony's doc.
+Used by Witch of Salzburg (ANIM\ANM0\ANM0.TOD) (oddly with [02h]=0000h)
+Used by Parappa (MagDemo01: PARAPPA\COMPO01.INT\3\*.TOD)
+Used by Macross VF-X 2 (MagDemo23: VFX2\DATA01\*.TOD and *.TOX)
+Used by Alice in Cyberland (ALICE.PAC\xxx_T*.FA\*.TOD)
+Unknown if/which other games are using the TOD format.
+
+ ____________________________________ HMD _____________________________________
+
+HMD - Hierarchical 3D Model, Animation and Other Data
+ 000h 4 ID (00000050h) ;same as in TOD, which CAN ALSO have MSBs=zero(!)
+ 004h 4 MAP FLAG (0 or 1, set when mapped via GsMapUnit() function)
+ 008h 4 Primitive Header Section pointer (whut?)
+ 00Ch 4 Number of Blocks
+ 010h 4*N Pointers to Blocks
+ ... Primitive Header section (required)
+ ... Coordinate section (optional)
+ ... Primitive section (required)
+This format is very complicated, see Sony's "File Formats" document for
+details.
+.HMD used by Brunswick Bowling (MagDemo13: THQBOWL\*).
+.HMD used by Soul of the Samurai (MagDemo22: RASETSU\0\OPT01T.BIN\0\0\*)
+.HMD used by Bloody Roar 2 (MagDemo22: LON\LON*.DAT\*, ST5\ST*.DAT\02h..03h)
+.HMD used by Ultimate Fighting Championship (MagDemo38: UFC\CU00.RBB\6Bh..EFh)
+Unknown if/which games other are using the HMD format.
+
+ ____________________________________ RSD _____________________________________
+
+RSD Files (RSD,PLY,MAT,GRP,MSH,PVT,COD,MOT,OGP)
+RSD files consist of a set of several files (RSD,PLY,MAT,etc). The files
+contain the "polygon source code" in ASCII text format, generated from Sony's
+"SCE 3D Graphics Tool". For use on actual hardware, the "RSDLINK" utility can
+be used to convert them to binary (TMD, PMD, TOD?, HMB?) files.
+ RSD Main project file
+ PLY Polygon Vertices (Vertices, Normals, Polygons)
+ MAT Polygon Material (Color, Blending, Texture)
+ GRP Polygon Grouping
+ MSH Polygon Linking ;\
+ PVT Pivot Rotation center offsets ; New Extended
+ COD Vertex Coordinate Attributes ; (since RSD version 3)
+ MOT Animation Information ;/
+ OGP Vertex Object Grouping ;-Sub-extended
+All of the above files are in ASCII text format. Each file is starting with a
+"@typYYMMDD" string in the first line of the file, eg. "@RSD970401" for RSD
+version 3. Vertices are defined as floating point values (as ASCII strings).
+There's more info in Sony's "File Formats" document, but the RSD stuff isn't
+used on retail discs. Except:
+ RSD/GRP/MAT/PLY (and DXF=whatever?) used on Yaroze disc (DTL-S3035)
+
+CDROM File Video STR Streaming and BS Picture Compression (Sony)
+----------------------------------------------------------------
+
+STR Files (movie streams)
+--> CDROM File Video Streaming STR (Sony)
+--> CDROM File Video Streaming STR Variants
+--> CDROM File Video Streaming Framerate
+--> CDROM File Video Streaming Audio
+--> CDROM File Video Streaming Chunk-based formats
+--> CDROM File Video Streaming Mis-mastered files
+Apart from the 20h-byte STR headers, movies basically consist of a series of BS
+files (see below).
+
+BS Files (Huffman compressed MDEC codes)
+BS stands for bitstream, which might refer to the use in STR files, or to the
+Huffman bitstreams.
+--> CDROM File Video BS Compression Versions
+--> CDROM File Video BS Compression Headers
+The header is followed by the bitstream...
+ v1/v2/v3/ea/iki --> first bit in bit15 of first halfword (good for psx)
+ v0 --> first bit in bit7 of first byte (not so good for psx)
+ (to use the same decoder for all version: swap each 2 bytes in v0)
+For each block, the bitstream contains one DC value, up to 63 AC values,
+terminated by EOB (end of block).
+--> CDROM File Video BS Compression DC Values
+--> CDROM File Video BS Compression AC Values
+Apart from being used in STR movies, BS can be also used to store single
+pictures:
+--> CDROM File Video BS Picture Files
+
+Wacwac (similar as BS, but with completely different Huffman codes)
+--> CDROM File Video Wacwac MDEC Streams
+
+Credits
+Thanks to Michael Sabin for info on various STR and BS variants:
+https://github.com/m35/jpsxdec/
+
+CDROM File Video Streaming STR (Sony)
+-------------------------------------
+
+.STR Sectors (with 20h-byte headers) (for MDEC Movies, or User data)
+ 000h 2 StStatus (0160h) (RV6Rh; R=Reserved=0, V=Version=1, 6=Fixed ID)
+ 002h 2 StType (0000h..7FFFh=User Defined, 8000h..FFFFh=System; 8001h=MDEC)
+ 004h 2 StSectorOffset (Sector number in the frame, 0=First)
+ 006h 2 StSectorSize (Number of sectors in the frame) (eg. 4 or 5)
+ 008h 4 StFrameNo (Frame number, 1=First) (except Viewpoint=0)
+ 00Ch 4 StFrameSize (in bytes, in this frame, excluding headers/padding)
+ When StType=0000h..7FFFh:
+ 010h 10h StUser (user defined data)
+ 020h 7E0h User data (more user defined data)
+ When StType=8001h=MDEC (the only system defined type) (with StStatus=0160h):
+ 010h 2 StMovieWidth (eg. 0140h)
+ 012h 2 StMovieHeight (eg. 00F0h)
+ 014h 4 StHeadM (reserved for system) (eg. 38000720h) ;\same as [020h-027h]
+ 018h 4 StHeadV (reserved for system) (eg. 00020001h) ;/from 1st STR sector
+ 01Ch 4 Unspecified (eg. 00000000h) (except Viewpoint<>0)
+ 020h 7E0h Data (in BS format) (or padding, when image is smaller than frame)
+The default file extension .STR is used by various games (though some games use
+other extensions, the .FMV files in Tomb Raider do also contain standard
+20h-byte .STR sector headers).
+
+Video Frames
+The video frames consist of BS compressed images (that is, all sectors have STR
+headers at 000h..01Fh, and the first sector of each frame does additionally
+contain a standard BS fileheader at offset 020h..027h).
+ See "CDROM File Video BS Compression" chapters
+Less common, there is also a format for streaming polygon animations instead of
+BS compressed bitmaps:
+--> CDROM File Video Polygon Streaming
+
+STR Resolution
+The Width/Height entries are almost always multiples of 16 pixels. But there
+are a few exceptions:
+ Height=260 (104h) in Star Wars Rebel Assault II, NTSC (S1\L01_PLAY.STR)
+ Height=200 (0C8h) in Perfect Assassin (DATA.JFS\CDV\*.STR)
+ Height=40 (028h) in Gran Turismo 1 (TITLE.DAT\*, MagDemo10 and MagDemo15)
+ Width=232 (0E8h) in Gran Turismo 1 (TITLE.DAT\*, MagDemo10 only)
+For such videos, the width/height of MDEC decompression buffer in RAM must be
+rounded up to multiples of 16 pixels (and the decompressed picture should be
+cropped to the STR header width/height before forwarding it to VRAM).
+Note: The extra scanlines are usually padded with the bottom-most scanline
+(except, Gran Turismo 1 has gray-padding in lower/right pixels). Ideally, one
+would repeat the bottom-most pixels in zigzag order.
+
+Subtitles
+Metal Gear Solid MGS\ZMOVIE.STR contains subtitles as text strings: The first
+sector of the .STR file is something custom (without STR header), the remaining
+movie consists of STR sectors with StType=0001h for subtitles and StType=8001h
+for picture frames.
+Unknown if other games are using the same method, or other methods.
+Obviously, subtitles could be also displayed as part of the compressed image,
+but text strings are much smaller, have better quality, and would also allow to
+support multiple languages.
+
+CDROM File Video Streaming STR Variants
+---------------------------------------
+
+STR ID Values
+ 2-byte 0160h ;Standard STR header
+ 1-byte 01h ;Ace Combat 3 Electrosphere
+ 4-byte "SMJ",01h ;Final Fantasy 8, Video
+ 4-byte "SMN",01h ;Final Fantasy 8, Audio/left
+ 4-byte "SMR",01h ;Final Fantasy 8, Audio/righ
+ 4-byte 0000000xh ;Judge Dredd
+ 4-byte DDCCBBAAh ;Crusader: No Remorse, older Electronic Arts
+ 4-byte 08895574h ;Chunk header in 1st sector only, Best Sports (demo)
+ 4-byte "VLC0" ;Chunk header in 1st sector only, newer Electronic Arts
+ 4-byte "VMNK" ;Chunk header in 1st sector only, Policenauts
+ 4-byte 01h,"XSP" ;Sentient header in 1st sector only
+ N-byre zero(es) ;Polygons? (in last 150Mbyte of PANEKIT.STR)
+
+STR Type values (for videos that do have STR ID=0160h):
+The official definition from Sony's File Formats document is as so;
+ 0000h..7FFFh=User Defined
+ 8000h..FFFFh=System (with 8001h=MDEC being the only officially defined type)
+In practice, the following values are used (of which, 8001h is most common).
+ 0000h=Polygon Video, Wacwac as Polygon Stream
+ 0000h=Polygon Video?, Army Men Air Attack 2 (MagDemo40: AMAA2\*.PMB)
+ 0000h=MDEC Video, Alice in Cyberland
+ 0001h=MDEC Video, Ridge Racer Type 4 (PAL version, 320x176 pix)
+ 0001h=Whatever extra data for XA-ADPCM streams (Bits Laboratory games)
+ 0001h=Whatever non-audio waverform? (3D Baseball)
+ 0001h=Subtitles, Metal Gear Solid MGS\ZMOVIE.STR
+ 0002h=Software-rendered video (without using MDEC/GTE) (Cyberia)
+ 0002h=MDEC Video, Wacwac with IntroTableSet
+ 0003h=MDEC Video, Wacwac with EndingTableSet
+ 0004h=MDEC Video, Final Fantasy 9 (MODE2/FORM2)
+ 0008h=SPU-ADPCM, AKAO audio (Final Fantasy 9)
+ 0000h=SPU-ADPCM, AKAO audio (Chrono Cross Disc 1, Legend of Mana)
+ 0001h=SPU-ADPCM, AKAO audio (Chrono Cross Disc 1, Legend of Mana)
+ 0100h=SPU-ADPCM, AKAO audio (Chrono Cross Disc 2)
+ 0101h=SPU-ADPCM, AKAO audio (Chrono Cross Disc 2)
+ 0000h=Whatever special, channel 0 header (Nightmare Project: Yakata)
+ 0400h=Whatever special, channel 1 header (Nightmare Project: Yakata)
+ 0001h=Whatever special, channel 0 data (Nightmare Project: Yakata)
+ 0401h=Whatever special, channel 1 data (Nightmare Project: Yakata)
+ 5349h=MDEC Video, Gran Turismo 1 and 2 (with BS iki)
+ 0078h=MDEC Ending Dummy (Mat Hoffman's Pro BMX (MagDemo48: MHPB\SHORT.STR)
+ 5673h=MDEC Leading Dummy (Mat Hoffman's Pro BMX (MagDemo48: MHPB\SHORT.STR)
+ 8001h=MDEC Video, Standard MDEC (most common type value)
+ 8001h=Polygon Video (Ape Escape) (same ID as standard MDEC)
+ 8001h=Eagle One: Harrier Attack various types (MDEC and other data)
+ 8001h=Dance series SPU-ADPCM streaming (with STR[1Ch]=DDCCBBAAh)
+ 8101h=MDEC Video, Standard MDEC plus bit8=FlagDisc2 (Chrono Cross Disc 2)
+
+ ______________________________________________________________________________
+
+Leading XA-ADPCM
+Most movies start with STR video sectors. But a few games start with XA-ADPCM:
+ Ace Combat 3 Electrosphere (*.SPB)
+ Alice in Cyber Land (*.STR)
+ Judge Dredd (*.IXA) ;and very small 4-byte STR header
+ ReBoot (MOVIES\*.WXA)
+Also, Aconcagua (Wacwac) has XA-ADPCM before Video (but, yet before that, it
+has 150 leading zerofilled sectors).
+Also, Porsche Challenge (SRC\MENU\STREAM\*.STR) starts with corrupted
+Subheaders, which may appear as leading XA-ADPCM (depending on how to
+interprete the corrupted header bits).
+
+Leading SPU-ADPCM
+ EA videos ;\
+ Crusader ; chunks
+ Policenauts ;/
+ AKAO videos
+
+Metal Gear Solid (MGS\ZMOVIE.STR, 47Mbyte)
+This is an archive dedicated to STR movies (with number of frames instead of
+filesize entries). Metal Gear Solid does also have cut-scenes with polygon
+animations (but those are supposedly stored elsewhere?).
+ 000h 4 Number of entries (4)
+ 004h N*8 File List
+ ... .. Zerofilled
+File List entries:
+ 000h 2 Unknown... decreasing values?
+ 002h 2 Number of Frames (same as last frame number in STR header)
+ 004h 4 Offset/800h (to begin of STR movie, with subtiltes in 1st sector)
+Disc 1 has four movies: The first one has a bit more than 12.5 sectors/frame,
+the other three have a bit more than 10 sectors/frame (eg. detecting the
+archive format could be done checking for entries wirh 8..16 sectors/frame).
+Example, from Disc 1:
+ 04 00 00 00
+ ED 97 9E 01 01 00 00 00 ;num sectors=1439h ;div19Eh=C.81h ;97EDh-6137h=36B6h
+ 37 61 86 01 3A 14 00 00 ;num sectors=0F41h ;div186h=A.03h ;6137h-38D0h=2867h
+ D0 38 10 03 7B 23 00 00 ;num sectors=1EA1h ;div310h=A.00h ;38D0h-2302h=15CEh
+ 02 23 73 02 1C 42 00 00 ;num sectors=1881h ;div273h=A.01h ;2302h-0000h=2302h
+The files in the ZMOVIE.STR archive start with subtitles in 1st sector (this is
+usually/always only one single sector for the whole movie):
+ 000h 2 STR ID (0160h) ;\
+ 002h 2 STR Type (0001h=Subtitles) ;
+ 004h 2 Sector number within Subtitles (0) ; STR
+ 006h 2 Number of Sectors with Subtitles (1) ; header
+ 008h 4 Frame number (1) ;
+ 00Ch 4 Data size counted in 4-byte units (same as [02Ch]/4) ;
+ 010h 10h Zerofilled ;/
+ 020h 4 Unknown (2) ;\
+ 024h 4 Unknown (1AAh, 141h, or 204h) ; Data
+ 028h 4 Unknown (00100000h) ; part
+ 02Ch 4 Size of all Subtitle entries in bytes plus 10h ;
+ 030h .. Subtitle entries ;/
+ ... .. Zeropadding to 800h-byte boundary ;-padding
+Subtitle entries:
+ 000h 4 Offset from current subtitle to next subtitle (or 0=Last subtitle)
+ 004h 4 First Frame number when to display the subtitle?
+ 008h 4 Number of frames when to display the subtitle?
+ 00Ch 4 Zero
+ 010h .. Text string, terminated by 00h
+ ... .. Zeropadding to 4-byte boundary
+The text strings are ASCII, with special 2-byte codes (80h,7Bh=Linebreak,
+1Fh,20h=u-Umlaut, etc).
+
+ ________________________ Customized STR Video Headers ________________________
+
+Viewpoint (with slightly modified STR header)
+ 008h 4 Frame number (0=First) ;<-- instead of 1=First
+ 01Ch 2 Unknown (always D351h) ;<-- instead of zero
+ 01Eh 2 Number of Frames in this STR file ;<-- instead of zero
+
+Capcom games
+Resident Evil 2 (ZMOVIE\*.STR, PL0\ZMOVIE\*.STR)
+Super Puzzle Fighter II Turbo (STR/CAPCOM15.STR)
+ 01Ch 4 Sector number of 1st sector of current frame ;<-- instead of zero
+
+Chrono Cross Disc 2 Video
+Chrono Cross Disc 1 does have normal STR headers, but Disc 2 has Type.bit8
+toggled:
+ 002h 2 STR Type (8101h=Disc 2) ;<-- instead of 8001h
+And, the Chrono Cross "final movie" does reportedly have "additional
+properties". Unknown, what that means, it does probably refer to the last movie
+on Chrono Cross Disc 2, which is quite huge (90Mbyte), and has lower resolution
+(160x112), and might have whatever "additional properties"?
+
+Need for Speed 3
+Need for Speed 3 Hot Pursuit (MOVIES\*.XA, contains videos, not raw XA-ADPCM)
+Jackie Chan Stuntmaster (FE\MOVIES\*.STR)
+With slightly modified STR headers:
+ 014h 4 Number of Frames (..excluding last some frames?) ;-instead BS[0..3]
+ 018h 4 Unlike the above modified entry, this is normal ;-copy of BS[4..7]
+
+ReBoot (MOVIES\*.WXA)
+This has leading XA-ADPCM, and customized STR header:
+ 014h 2 Type (0000h=Normal, 01FFh=Empty frames at end of video)
+ 016h 2 Number of Frames (excluding empty ones at end of video)
+ 018h 8 Zerofilled
+
+Gran Turismo 1 (230Mbyte STREAM.DAT) and Gran Turismo 2 (330Mbyte STREAM.DAT)
+These two games use BS iki format, and (unlike other iki videos) also special
+STR headers:
+ 002h 2 STR Type (5349h) ("IS") ;-special (instead 8001h)
+ 010h 2 Total number of frames in video ;-special (instead width)
+ 012h 2 Flags (bit15=1st, bit14=last) ;-special (instead height)
+ 014h 8 Zero ;-special (instead BS header copy)
+ 020h 7E0h Data (in BS iki format) ;-BS iki header (with width/height)
+Caution: The STR header values aren't constant throughout the frame:
+ Namely, flags in [012h] are toggled on first/last sector of each frame,
+ and of course [04h] does also increase per sector.
+
+PGA Tour 96, 97, 98 (VIDEO\..\*.XA and ZZBUFFER\*.STR)
+Used by all movies in PGA Tour 96, 97 (and for the ZZBUFFER\BIGSPY.STR dummy
+padding movie in PGA Tour 98).
+The videos have normal BS v2 data, but the Frame Size entry is 8 smaller than
+usually. As workaround, always load [0Ch]+8 for all movies with standard STR
+headers (unless that would exceed [06h]*7E0h).
+ 00Ch 4 Frame Size-8 (ie. excluding 8-byte BS header) ;instead of Size-0
+The padding videos in ZZBUFFER folder have additional oddities in STR header:
+ ZZBUFFER\SPY256.STR [14h..1Fh]=normal copy of 8-byte BS v2 header and zero
+ ZZBUFFER\SPYGLASS.STR [14h..1Fh]=zerofilled ;\BS v1
+ ZZBUFFER\SPYTEST.STR [14h..1Fh]=00 00 10 00 00 00 00 09 00 00 07 EE ;/
+ ZZBUFFER\BIGSPY.STR Used in PGA Tour 98 (instead of above three files)
+SPYTEST.STR has nonsense quant values exceeding the 0000h..003Fh range (first
+frame has quant=00B1h, and later frames go as high as quant=FFxxh, that kind of
+junk is probably unrelated to BS fraquant). The oddities for SPYTEST.STR do
+also occur in some frames in PGA Tour 98 BIGSPY.STR. Anyways, those ZZBUFFER
+files seem to be only unused padding files.
+
+Alice in Cyber Land (*.STR)
+Note: First sector contains XA-ADPCM audio (video starts in 2nd sector).
+ STR Sector Header:
+ 002h 2 STR Type (0000h=Alice in Cyber Land video) ;-special
+ 008h 4 Frame number (1=First) (bit15 set in last frame, or FFFFh)
+ 010h 10h Zerofilled (instead width/height and BS header copy) ;-special
+ 020h 7E0h Data (in BS v2 format)
+Frames are always 320x240.
+The frame number of the last used frame of a movie has the bit15 set. After
+that last frame, there are some empty frame(s) with frame number FFFFh.
+For some reason there are "extra audio sectors in between movies" (uh?).
+Many of the movies have a variable frame rate. All movies contain frames
+sequences that match one of the following frame rates: 7.5 fps, 10 fps, 15 fps,
+30 fps.
+
+Encrypted iki (Panekit - Infinitive Crafting Toy Case)
+ 014h 8 Copy of decrypted BS header (instead of encrypted BS header)
+
+Princess Maker: Yumemiru Yousei (PM3.STR)
+Parappa (Japanese Demo version only) (S0/GUIDE.STR)
+These files do have BS ID=3000h (except, the first and last some frames have
+nromal ID=3800h). The STR header is quite normal (apart from reflecting the odd
+BS ID):
+ 016h 2 Copy of BS ID, 3000h in most frames (instead of 3800h)
+ 020h 7E0h Data (in BS format, also with BS ID 3000h, instead of 3800h)
+
+Starblade Alpha and Galaxian 3
+These movies have Extra stuff in the data section. The STR header is quite
+normal (apart from reflecting the Extra stuff):
+ 00Ch 4 Frame Size in bytes (=size of ExtraHeader + BsData + ExtraData)
+ 014h 4 Copy of Extra Header ;instead of BS[0..3]
+ 018h 4 Copy of BS[0..3] ;instead of BS[4..7]
+ 020h 7E0h Data (ExtraHeader + BsData + ExtraData)
+The data part looks as so:
+ 000h 2 Size of BS Data area (S1) ;\Extra Header
+ 002h 2 Size of Extra Data area (S2) ;/
+ 004h S1 BS Data (in BS v3 format) ;-BS Data
+ .. S2 Extra Data (unknown purpose) ;-Extra Data
+Note: Starblade Alpha does use that format for GAMEn.STR and NAME.STR in FLT
+and TEX folders (the other movies in that game are in normal STR format).
+
+Largo Winch: Commando SAR (FMV\NSPIN_W.RNG)
+This is a somewhat "normal" movie, without audio, and with the STR headers
+moved to the begin of the file:
+ 000h Nx20h STR Headers ;size = filesize/800h*20h
+ ... Nx7E0h Data ;size = filesize/800h*7E0h
+Note: The movie contains the rotating "W" logo, which is looped in Start
+screen.
+
+Player Manager (1996, Anco Software) (FILMS\1..3\*.STR)
+ 006h 2 Number of Sectors in this Frame-1 (8..9 = 9..10 sectors)
+ 00Ch 4 Frame Size in bytes (8..9*7E0h = 3F00h or 46E0h)
+ 010h 2 Bitmap Width (always F0h)
+ 012h 2 Bitmap Width (always 50h)
+ 014h 0Ch Zerofilled (instead copy of BS header or copy of Extra header)
+ 020h 7E0h Data (Extra Stuff, BS v2 data, plus Unused stuff)
+The data part occupies 9-10 sectors, consisting of:
+ 0000h Extra Stuff (7E0h bytes, whatever, often starts with 00,FF,00,FF,..)
+ 07E0h BS v2 data (3720h or 3F00h bytes, including FFh-padding)
+ ... Unused Sector (7E0h bytes, same as in previous frame or zerofilled)
+The compressor tries to match the picture quality to the number of sectors per
+frame, but it's accidentally leaving the last sector unused:
+ For 9 sectors: Only 1..7 are used, sector 8 is same as in previous frame
+ For 10 sectors: Only 1..8 are used, sector 9 is zerofilled
+Apart from the odd format in FILMS\1..3\*.STR, the game does also have normal
+videos in FILMS\*.STR.
+
+Chiisana Kyojin Microman (DAT\STAGE*\*.MV)
+The .MV files have 5 sectors/frame: Either 5 video sectors without audio, or
+4-5 video sectors plus XA-ADPCM audio (in the latter case, audio is in each 8th
+sector (07h,0Fh,17h,1Fh,etc), hence having filesize rounded up to N*8 sectors):
+ Filesize = 800h*((NumberOfFrames*5)) ;5 sectors, no xa-adpcm
+ Filesize = 800h*((NumberOfFrames*5+7) AND not 7) ;4-5 sectors, plus xa-adpcm
+Caution: The STR header values aren't constant throughout the frame:
+ Sector 0: [10h] = Number of Frames, [12h]=Junk
+ Sector 1: [10h] = Junk, [12h]=0
+ Sector 2: [10h] = Junk, [12h]=Junk
+ Sector 3: [10h] = Junk, [12h]=Same as below (Bitmap Height)
+ Below ONLY when having 5 sectors per frame:
+ Sector 4: [10h] = Bitmap Width (140h) [12h]=Bitmap Height (D0h)
+ That is, frames with 4 sectors do NOT have any Bitmap Width entry
+ (the duplicated Height entry in sector 3 exists, so one could compute
+ Width=NumMacroBlocks*100h/Height, or assume fixed Width=320, Height=208).
+The Junk values can be zero, or increase/decrease during the movie, some or all
+of them seem to be sign-expanded from 12bit (eg. increasing values can wrap
+from 07xxh to F8xxh).
+Apart from the odd DAT\STAGE*\*.MV files, the game does also have .STR files
+with normal STR headers and more sectors per frame (DAT\STAGE16,21,27\*.STR,
+DAT\OTHER\*.STR, DAT\OTHER\CM\*.STR, and MAT\DAT\*.STR).
+
+Black Silence padding
+Used by Bugriders: The Race of Kings (MOVIE\*XB.STR)
+Used by Rugrats Studio Tour (MagDemo32: RUGRATS\DATA\OPEN\*B.STR)
+ Each movie file is followed by dummy padding file. For example, in Bugriders:
+ MOVIE\*XA.STR Movie clip (with correct size, 320x192)
+ MOVIE\*XB.STR Black Silence padding (wrong size 640x192, should be 320x192)
+The names are sorted alphabetically and exist in pairs (eg. CHARMXA.STR and
+CHARMXB.STR), and the disc sectors are following the same sort order.
+The padding files contain only black pixels and silent XA-ADPCM sectors, with
+following unique STR header entries, notably with wrong Width entry (the MDEC
+data contains only 320x192 pixels).
+ 00Ch 4 Frame Size (087Ch)
+ 010h 2 Bitmap Width (wrongly set to 640, should be 320)
+ 012h 2 Bitmap Height (192)
+ 014h 2 MDEC Size (05A0h)
+ 016h 2 BS ID (3800h)
+ 018h 2 BS Quant (0001h)
+ 01Ah 2 BS Version (0002h)
+ Filesize is always 44Fh sectors (about 2.2Mbyte per *XB.STR file)
+The huge 7 second padding is a very crude way to avoid the next movie to be
+played when not immediately pausing the CDROM at end of current movie.
+
+Ridge Racer Type 4 (only PAL version) (R4.STR)
+The 570Mbyte R4.STR file contains XA-ADPCM in first three quarters, and two STR
+movies in last quarter:
+ 1st NTSC/US movie: 320x160 pix, 0F61h frames, 4-5 sectors/frame, normal STR
+ 1st PAL/EUR movie: 320x176 pix, 0CD0h frames, 5-6 sectors/frame, special STR
+ 2nd NTSC/US movie: 320x160 pix, 1D6Ah frames, 4-5 sectors/frame, normal STR
+ 2nd PAL/EUR movie: 320x160 pix, 18B5h frames, 5-6 sectors/frame, normal STR
+As seen above, the PAL movies have lower framerate. And, the 1st PAL movie has
+higher resolution, plus some other customized STR header entries:
+ 002h 2 STR Type (0001h=Custom, 176pix PAL video) ;instead of 8001h
+ 006h 2 Number of Sectors in this Frame (always 5..6)
+ 00Ch 4 Frame Size (always 2760h or 2F40h, aka 7E0h*5..6)
+ 012h 2 Bitmap Height (00B0h, aka 176 pixels) ;instead of 00A0h
+ 014h 8 Zerofilled ;instead BS[0..7]
+ 020h 7E0h Data (in BS v3 format, plus FFh-padding)
+That is, the special video is standard MDEC, the only problem is detecting it
+as such (despite of the custom STR Type entry).
+
+Mat Hoffman's Pro BMX (MagDemo48: MHPB\SHORT.STR)
+This contains a normal MDEC movie, but with distorted "garbage" in first and
+last some sectors.
+ 1st sector STR Type 5673h (Leading Dummy) ;\
+ 2nd sector STR Type 8001h (distorted/empty MDEC) ; junk
+ 3rd..6th sector STR Type 8001h (distorted/garbage MDEC) ;/
+ 7th sector and up STR Type 8001h (normal MDEC, with odd [01Ch]) ;-movie
+ Last 96h sectors STR Type 0078h (Ending Dummy) ;-junk
+1st Sector:
+ 002h 2 STR Type (5673h=Leading Dummy)
+ 004h 4 Whatever (0004000Ch)
+ 008h 4 Whatever (0098967Fh)
+ 00Ch 4 Frame Size (always 100h)
+ 010h 7F0h EAh-filled
+2nd Sector:
+ 002h 2 STR Type (8001h=Normal MDEC ID, but content is empty)
+ 004h 4 Whatever (0004000Ch) ;\
+ 008h 4 Whatever (0098967Fh) ; same as in 1st sector
+ 00Ch 4 Frame Size (always 100h) ; (but ID at [002h] differes)
+ 010h 7F0h EAh-filled ;/
+3rd-6th Sector:
+ 002h 2 STR Type (8001h=Normal MDEC ID, but content is distorted)
+ 004h 2 Sector number within current Frame (always 0)
+ 006h 2 Number of Sectors in this Frame (always 1)
+ 008h 4 Frame number (increasing, 1..4 for 3rd..6th sector)
+ 00Ch 4 Frame Size (always 7D0h)
+ 010h 10h EAh-filled
+ 020h 7D0h Unknown (random/garbage?)
+ 7F0h 10h EAh-filled
+7th Sector and up (almost standard MDEC):
+ Caution: The STR header values aren't constant throughout the frame:
+ Entry entry [01Ch] is incremented per sector (or wraps to 0 in new section).
+ 01Ch 4 Increasing sector number (within current movie section or so)
+Last 96h Sectors:
+ 002h 2 STR Type (0078h=Ending Dummy)
+ 004h 2 Sector number within current Frame (always 0)
+ 006h 2 Number of Sectors in this Frame (always 1)
+ 008h 4 Frame number (increasing, in last 96h sectors)
+ 00Ch 4 Frame Size (always 20h)
+ 010h 2 Bitmap Width (always 40h)
+ 012h 2 Bitmap Height (always 40h)
+ 014h 7ECh Zerofilled
+
+Final Fantasy VII (FF7) (MOVIE\*.MOV and MOVIE\*.STR)
+These movies have Extra stuff in the data section. The STR header is quite
+normal (apart from reflecting the Extra stuff):
+ 00Ch 4 Frame Size in bytes (including 28h-byte extra stuff)
+ 014h 8 Copy of Extra data [0..7] :-instead of BS header[0..7]
+ 020h 7E0h Data (ExtraData + BsData)
+The data part looks as so:
+ 000h 28h Extra data (unknown purpose, reportedly "Camera data" ... whut?)
+ 028h .. BS Data (in BS v1 format)
+
+Final Fantasy IX (FF9) (*.STR and *.MBG)
+There are several customized STR header entries:
+ 002h 2 STR Type (0004h=FF9/Video) ;instead of 8001h
+ 004h 2 Sector number within current Frame (02h..num-1) (2..9 for video)
+ 006h 2 Total number of Audio+Video sectors in this frame (always 0Ah)
+ 00Ch 4 Frame Size/4 (of BS data, excluding MBG extra) ;instead of Size/1
+ 014h 8 Copy of BS[0..7] from 8th video sector ;instead 1st sector
+ 01Ch 2 Usually 0000h (or 0004h in some MBG sectors) ;inszead of 0000h
+ 01Eh 2 Usually 0000h (or 3xxxh in some MBG sectors) ;inszead of 0000h
+ 020h 8F4h Data (in BS v2 format, plus MBG extra data, if any)
+Caution: The STR header values aren't constant throughout the frame:
+ Namely, entry [1Ch..1Fh]=nonzero occurs only on the sector that does contain
+ the end of BS data (=and begin of MBG extra data), and of course [04h] does
+ also increase per sector.
+Sector ordering has BS data snippets arranged backwards, for example, if BS
+data does occupy 2.5 sectors:
+ [04h]=00h-01h 1st-2nd audio sector, SPU-ADPCM (see Audio streaming chapter)
+ [04h]=02h-06h 1st-5th video sector, unused, [020h..913h] is FFh-filled
+ [04h]=07h 6th video sector, contains end of BS data and MBG extra, if any
+ [04h]=08h 7th video sector, contains middle of BS data
+ [04h]=09h 8th video sector, contains begin of BS data
+Sector type/size, very unusually with FORM2 sectors:
+ Audio sectors are MODE2/FORM1 (800h bytes, with error correction)
+ Video sectors are MODE2/FORM2 (914h bytes, without error correction)
+Huffman codes are standard BS v2, with one odd exception: MDEC 001Eh/03E1h
+(run=0, level=+/-1Eh) should be usually encoded as 15bit Huffman codes, FF9 is
+doing that for 001Eh, but 03E1h is instead encoded as 22bit Escape code:
+ 000000000100010 MDEC=001Eh (run=0, level=+1Eh) ;-normal (used)
+ 000000000100011 MDEC=03E1h (run=0, level=-1Eh) ;-normal (not used)
+ 0000010000001111100001 MDEC=03E1h (run=0, level=-1Eh) ;-escape (used)
+There are two movie variants: *.STR and *.MBG. Most MBG files (except
+SEQ02\MBG102.MBG) contain extra MBG info in [01Ch..01Fh] and extra MBG data
+appended after the BS data. If present, the appended MBG data is
+often/always(?) just these 28h-bytes:
+ FF FF FF FF FE FF FE 41 AD AD AD AD AD AD AD AD
+ AD AD AD AD AD AD AD AD AD AD AD AD AD AD AD AD
+ AD AD AD AD AD AD AD AD
+ (followed by FF's, which might be padding, or part of the extra data)
+Unknown if some sectors contain more/other MBG data, perhaps compressed BG
+pixel-depth values for drawing OBJs in front/behind BG pixels?
+
+ _______________________ Non-standard STR Video Headers _______________________
+
+Final Fantasy VIII (FF8)
+Video frames are always 320x224. The video frames are preceeded by two
+SPU-ADPCM audio sectors.
+ 000h 4 ID "SMJ",01h=Video
+ 004h 1 Sector number within current Frame (02h..num-1) (2..9 for video)
+ 005h 1 Total number of Audio+Video sectors in this frame, minus 1 (9)
+ 006h 2 Frame number (0=First)
+ 008h 7F8h Data (in BS v2 format)
+
+Ace Combat 3 Electrosphere (in 520Mbyte ACE.SPH/SPB archive)
+The videos start with one XA-ADPCM sector, followed by the first Video sector.
+ STR Sector Header:
+ 000h 1 Always 01h
+ 001h 1 Sector number within current Frame (00h..num-1) (8bit)
+ 002h 2 Number of Sectors in this Frame
+ 004h 2 Unknown (1 or 3)
+ 006h 2 Frame number (decreasing, 0=Last)
+ 008h 2 Bitmap Width in pixels ;\130hxE0h or 140hxB0h or 80hx60h
+ 00Ah 2 Bitmap Height in pixels ;/
+ 00Ch 4 Zero
+ 010h 2 Zero, or decreasing timer (decreases approx every 2 sectors)
+ 012h 2 Zero, or decreasing timer (decreases approx every 1 sector)
+ 014h 3 Zero
+ 017h 1 Zero, or increases with step 2 every some hundred sectors
+ 018h 2 Zero, or Timer (increments when [1Ah] wraps from 04h to 01h)
+ 01Ah 1 Zero, or Timer (increments when [1Bh] wraps from 5Fh to 00h]
+ 01Bh 1 Zero, or Timer (increments approx every 1 sector)
+ 01Ch 2 Zero, or Whatever (changes to whatever every many hundred sectors)
+ 01Eh 2 Zero, or 0204h
+ 020h 7E0h Data (in BS v3 format)
+Caution: The STR header values aren't constant throughout the frame:
+ Namely, entry [10h..1Fh] can change within the frame (happens in japanese
+ version), and of course [01h] does also increase per sector.
+The Japanese version may be the only game that has two streaming videos running
+in parallel on different channels.
+That means, non-japanese version is different...?
+
+Judge Dredd (1998, Gremlin) (CUTS\*.IXA and LEVELS\*\*.IXA)
+This is a lightgun-game with "interactive movies". The gameplay consists of
+running on a fixed path through a scene with pre-recorded background graphics,
+the only player interaction is aiming the gun at other people that show up in
+that movie scene. There are two movie types:
+ LEVELS\*\*.IXA - Interactive gameplay movies
+ CUTS\*.IXA - Non-interactive cut-scene movies
+Both CUTS and LEVELS have unusually small 4-byte STR headers:
+ 000h 4 Sector number within current Frame (LEVELS=0..8, or CUTS=0..9)
+ 004h 7FCh Data (see below)
+Data for CUTS is 320x240pix (10 sectors per frame):
+ Note: CUTS videos have 2 leading XA-ADPCM sectors
+ 000h .. BS Data (in BS v2/v3 format) ;-BS picture
+Data for LEVELS is 320x352pix plus extra stuff (9 sectors per frame):
+ Note: LEVELS videos have 1 leading XA-ADPCM sector
+ 000h 4 Offset to BS Data (always 28h) ;\
+ 004h 4*6 Offsets to Extra Stuff 1..6 ; extra header
+ 01Ch 0Ch Zerofilled ;/
+ 028h .. BS Data (in BS v2/v3 format) ;-BS picture
+ ... .. Extra Stuff 1..6 ;-extra data
+The unusual 320x352pix resoltution contains a 320x240pix BG image, with
+additional 320x112pix texture data appended at the bottom.
+Extra Stuff 1..6 does supposedly contain info for animating enemies and/or
+backgrounds.
+
+______________________________________________________________________________
+
+iki
+The .iki video format (found in files with .IKI or .IK2 extension) is used in
+several games made by Sony. iki movie sectors have some different properties:
+ * There are only as many iki video sectors as needed to hold all the
+ frame's data. Remaining sectors are null.
+ * The first sector's Submode.Channel starts at zero, then increments for
+ each sector after that, and resets to zero after an audio sector.
+ * IK2 videos can also have variable frame rates that are very inconsistent.
+
+CDROM File Video Streaming Framerate
+------------------------------------
+
+According to Sony, BS encoded 320x240pix videos can be played at 30fps (with
+cdrom running at double speed).
+
+STR Frame Rate
+As a general rule, the frame rate is implied in CDROM rotation speed (150 or 75
+sectors per second, minus the audio sectors, divided by the number of sectors
+per video frame).
+
+Fixed/Variable Framerates
+The frame can drop on video frames that contain more sectors than usually.
+Video frames that require fewer sectors than often padded with zerofilled
+sectors. However, some games don't have that padding, so they could end up
+reeceiving up to 150 single-sector frames per second; the actual framerate is
+supposedly slowed down to 60Hz or less via Vblank timer (and with the CDROM
+reading getting paused when the read-ahead buffer gets full).
+
+Audio Samplerate
+XA-ADPCM audio contains samplerate info (in the FORM2 subheader), the
+samplerate versus amount of audio sectors can be used to compute the CDROM
+rotation speed.
+There are two exceptions: Some movies don't have any audio at all, and some
+movies use SPU-ADPCM instead of XA-ADPCM. In the latter case, the SPU Pitch
+(samplerate) may (or may not) be found somewhere in the audio sector headers.
+
+CDROM Rotation speed
+As said above, the speed can be often detected via audio sample rate.
+Otherwise, the general rule is that most PSX games are used 2x speed (150
+sectors/second). But, there are a few games with 1x speed (see below).
+
+CDROM Single speed (75 sectors/frame)
+Here are probably most of the USA games with videos at 1x speed.
+ 007 - The World Is Not Enough
+ 1Xtreme
+ Arcade Party Pak
+ Atari Anniversary Edition Redux
+ Blast Radius
+ Blue's Clues - Blue's Big Musical
+ Chessmaster II
+ Chronicles of the Sword
+ Civilization II
+ Colin McRae Rally
+ Creatures - Raised in Space
+ Cyberia
+ Demolition Racer
+ Dune 2000
+ ESPN Extreme Games
+ FIFA Soccer 97
+ Fade to Black
+ Family Connection - A Guide to Lightspan
+ Fear Effect
+ Fox Hunt
+ Interactive CD Sampler Volume 1
+ Jade Cocoon - Story of the Tamamayu
+ Jeopardy! 2nd Edition
+ Juggernaut
+ Krazy Ivan
+ MTV Sports - Skateboarding featuring Andy Macdonald
+ MTV Sports - T.J. Lavin's Ultimate BMX
+ Medal of Honor
+ Medal of Honor - Underground
+ Official U.S. PlayStation Magazine Demo Disc 23
+ Planet of the Apes
+ PlayStation Underground Number 2
+ Shockwave Assault
+ Starblade Alpha
+ Starwinder - The Ultimate Space Race
+ Str.at.e.s. 1 - Match-A-Batch
+ Str.at.e.s. 5 - Parallel Lives!
+ Str.at.e.s. 7 - Riddle Roundup!
+ The X-Files
+ Top Gun - Fire at Will!
+ Um Jammer Lammy
+ Uprising X
+ Wheel of Fortune - 2nd Edition
+ Williams Arcade's Greatest Hits
+
+CDROM File Video Streaming Audio
+--------------------------------
+
+Audio Stream
+STR movies are usually interleaved with XA-ADPCM sectors (the audio sectors are
+automatically decoded by the CDROM hardware and consist of raw ADPCM data
+without STR headers).
+--> CDROM File Audio Streaming XA-ADPCM
+However, there are also movies without audio. And a few movies with SPU-ADPCM
+audio.
+
+SPU-ADPCM in Chunk-based formats
+--> CDROM File Video Streaming Chunk-based formats
+
+SPU-ADPCM in Chrono Cross/Legend of Mana Audio Sector
+Chrono Cross Disc 1 (HiddenDirectory\1793h..17A6h)
+Chrono Cross Disc 2 (HiddenDirectory\1793h..179Dh)
+Legend of Mana (MOVIE\*.STR, except some movies without audio)
+ 000h 2 STR ID (0160h)
+ 002h 2 STR Type (0000h, 0001h, 0100h, or 0101h)
+ 0000h=Legend of Mana, Audio normal sectors
+ 0001h=Legend of Mana, Audio sectors near end of movie
+ 0000h=Chrono Cross Disc 1, Audio.left?
+ 0001h=Chrono Cross Disc 1, Audio.right?
+ 0100h=Chrono Cross Disc 2, Audio.left?
+ 0101h=Chrono Cross Disc 2, Audio.right?
+ 004h 2 Sector number in Frame (0=Audio.left?, 1=Audio.right?)
+ 006h 2 Number of Audio sectors in this frame (always 2)
+ 008h 4 Frame number (1=First)
+ 00Ch 4 Unused (Chrono: FFh-filled or Mana: 00000FC0h=2x7E0h=Framesize?)
+ 010h 10h Unused (Chrono: FFh-filled or Mana: 00h-filled)
+ 020h 60h Unused (FFh-filled)
+ 080h 4 ID "AKAO"
+ 084h 4 Frame number (0=First)
+ 088h 8 Unused (zerofilled)
+ 090h 4 Remaining Time (step 690h) (can get stuck at 0340h or 0B20h at end)
+ 094h 4 Zero
+ 098h 4 Unknown (11h)
+ 09Ch 4 Pitch (1000h=44100Hz)
+ 0A0h 4 Number of bytes of audio data (always 690h)
+ 0A4h 2Ch Unused (zerofilled)
+ 0D0h 690h Audio (10h-byte SPU-ADPCM blocks) (1680 bytes)
+ 760h A0h Unused (10h-byte SPU-ADPCM blocks with flag=03h and other bytes=0)
+Note: The Chrono/Mana STR files start with Audio frames in first sector
+(except, some Legend of Mana movies don't have any Audio, and do start with
+Video frames).
+
+SPU-ADPCM in Final Fantasy VIII (FF8)
+ 000h 4 ID "SMN",01h=Audio/left, "SMR",01h=Audio/right
+ 004h 1 Sector number in Frame (0=Audio.left, 1=Audio.right)
+ 005h 1 Total number of Audio+Video sectors in this frame, minus 1 (1 or 9)
+ 006h 2 Frame number (0=First)
+ 008h E8h Unknown (camera data?) (232 bytes)
+ 0F0h 6 Audio ID (usually "MORIYA", sometimes "SHUN.M")
+ 0F6h 0Ah Unknown (10 bytes) (reportedly 10 bytes at offset 250 = FAh ?????)
+ 100h 4 ID "AKAO"
+ 104h 4 Frame number (0=First)
+ 108h 14h Unknown (20 bytes)
+ 11Ch 4 Pitch (1000h=44100Hz)
+ 120h 4 Number of bytes of audio data (always 690h)
+ 124h 2Ch Unknown (44 bytes)
+ 150h 20h Unknown (32 bytes)
+ 170h 690h SPU-ADPCM Audio data (690h bytes)
+There is one special case on disc 1: a movie with no video. Each 'frame'
+consists of two sectors: the first is the left audio channel, the second is the
+right audio channel.
+
+SPU-ADPCM in Final Fantasy IX (FF9) (*.STR and *.MBG)
+The FF9 audio sectors are normal MODE2/FORM1 sectors (unlike the FF9 video
+sectors, which are MODE2/FORM2).
+ 000h 2 STR ID (0160h)
+ 002h 2 STR Type (0008h=FF9/Audio)
+ 004h 2 Sector number in Frame (0=Audio.left, 1=Audio.right)
+ 006h 2 Total number of Audio+Video sectors in this frame (always 0Ah)
+ 008h 4 Frame number (1=First)
+ 00Ch 4 Zero
+ 010h 1 Audio flag? (00h=No Audio, 01h=Audio)
+ 011h 4Fh Zerofilled --- XXX or whatever (when above is 00h)
+ 060h 4 Number of Frames in this STR file
+ 064h 1Ch EEh-filled
+ Below 780h bytes are all zerofilled when [10h]=00h (no audio)
+ Below 780h bytes are reportedly all ABh-filled "in the last frame of a movie
+ on Disc 4" (unknown which movie, and if that occurs in other movies, too)
+ 080h 4 ID "AKAO"
+ 084h 4 Frame number (0=First)
+ 088h 14h Unknown (20 bytes)
+ 09Ch 4 Pitch (116Ah=48000Hz) (or 1000h=44100Hz in final movie)
+ 0A0h 4 Number of bytes of audio data (0, 720h, 730h, or 690h=final movie)
+ 0A4h 2Ch Unknown (44 bytes)
+ 0D0h 730h SPU-ADPCM audio (plus leftover/padding when less than 730h bytes)
+
+Dance series SPU-ADPCM streaming (bigben interactive, DATA.PAK\stream\*.str)
+This format is used for raw SPU-ADPCM streaming (without video).
+SLES-04121 Dance: UK
+SLES-04161 Dance: UK eXtra TraX
+SLES-04129 Dance Europe
+SLES-04162 All Music Dance! (Italy)
+ 000h 2 STR ID (0160h)
+ 002h 2 STR Type (8001h, same as MDEC)
+ 004h 2 Sector number within current Frame (0000h..num-1)
+ 006h 2 Number of Sectors in this Frame (always 9)
+ 008h 4 Frame number (0=First)
+ 00Ch 4 Frame Size in bytes (always 4000h)
+ 010h 4 Whatever (always 00A000A0h, would be width/height if it were video)
+ 014h 8 Zerofilled
+ 01Ch 4 Special ID (always DDCCBBAAh for Dance audio)
+ 020h 7E0h Data (in SPU-ADPCM format, mono, 22200Hz aka Pitch=07F5h)
+Note: Sector 0..8 contain 9*7E0h=46E0h bytes data per frame, but only 4000h
+bytes are used (the last 6E0h bytes in sector 8 are same as in sector 7).
+
+Raw SPU-ADPCM Streaming
+Some games are using raw SPU-ADPCM for streaming. That is, the file is
+basically a normal .VB file, but it can be dozens of megabytes tall (ie. too
+large to be loaded into RAM all at once).
+ Disney's The Emperor's New Groove (MagDemo39: ENG\STREAM\*.CVS)
+ Disney's Aladdin in Nasira's Revenge (MagDemo46: ALADDIN\STREAM\*.CVS)
+
+CDROM File Video Streaming Chunk-based formats
+----------------------------------------------
+
+Newer Electronic Arts videos (EA)
+EA videos are chunk based (instead of using 20h-byte .STR headers). The next
+chunk starts right at the end of the previous chunk (without padding to sector
+boundaries).
+ STR Sector Header:
+ No STR Sector header (first sector starts directly with "VLC0" chunk)
+ VLC0 Chunk (at begin of movie file):
+ 000h 4 Chunk ID "VLC0"
+ 004h 4 Chunk Size (always 1C8h) (big-endian)
+ 008h 1C0h 16bit MDEC values for E0h huffman AC codes (little-endian)
+ MDEC Chunks (video frames):
+ 000h 4 Chunk ID "MDEC" ;\
+ 004h 4 Chunk Size (...) (big-endian) ; custom chunk header,
+ 008h 2 Bitmap Width in pixels (big-endian) ; instead of STR header
+ 00Ah 2 Bitmap Height in pixels (big-endian) ;
+ 00Ch 4 Frame Number (starting at 0) (big-endian) ;/
+ 010h .. Data (in BS v2 format, but using custom Huffman codes from VLC0)
+ ... .. Zeropadding to 4-byte boundary
+ Audio Chunks (au00/au01):
+ 000h 4 Chunk ID ("au00"=normal, "au01"=last audio chunk)
+ 004h 4 Chunk Size (...) (big-endian)
+ 008h 4 Total number of 2x4bit samples in previous chunks (big-endian)
+ 00Ch 2 Unknown (always 800h) (maybe Pitch: 800h=22050Hz) (big-endian)
+ 00Eh 2 Unknown (always 200h) (big-endian)
+ ... .. SPU-ADPCM audio data, left (0Fh bytes per sample block)
+ ... .. SPU-ADPCM audio data, right (0Fh bytes per sample block)
+ ... .. Garbagepadding to 4-byte boundary
+ Note: SPU-ADPCM does normally have 10h-byte blocks, but in this case,
+ the 2nd byte (with loop flags) is omitted, hence only 0Fh-byte blocks.
+ Zero Chunk (zeropadding at end of file, exists only in some EA videos):
+ 000h .. Zeropadding
+
+Older Electronic Arts videos
+Crusader: No Remorse (1996 Origin Systems) (MOVIES\*.STR)
+Soviet Strike (1996 Electronic Arts)
+Battle Stations (1997 Electronic Arts)
+Andretti Racing (1996 Electronic Arts)
+ STR Sector Header:
+ 000h 4 ID (DDCCBBAAh) (aka AABBCCDDh big-endian)
+ 004h 4 Sector number within STR file (0=First, up to Filesize/800h-1)
+ 008h 7F8h Data (video and audio chunks, see below) (first chunk is "ad20")
+ Video Chunks (MDEC):
+ 000h 4 Chunk ID "MDEC" ;\
+ 004h 4 Chunk Size (...) (big-endian) ;
+ 008h 2 Bitmap Width in pixels (big-endian) ; custom chunk header
+ 00Ah 2 Bitmap Height in pixels (big-endian) ;
+ 00Ch 4 Frame Number (starting at 0) (big-endian) ;/
+ 010h .. Data (in BS v2 format) ;-standard BS v2 data
+ Audio Chunks (ad20/ad21) (22050Hz stereo):
+ 000h 4 Chunk ID ("ad20"=normal, "ad21"=last audio chunk)
+ 004h 4 Chunk Size (1A50h or 1A70h) (big-endian)
+ 008h 4 Total number of 2x4bit samples in previous chunks (big-endian)
+ 00Ch 2 Unknown (always 800h) (maybe Pitch: 800h=22050Hz) (big-endian)
+ 00Eh 2 Unknown (always 200h) (big-endian)
+ 010h .. SPU-ADPCM audio data, left (10h bytes per sample block)
+ ... .. SPU-ADPCM audio data, right (10h bytes per sample block)
+ Last STR Sector:
+ 000h 18h FFh-filled (aka 8-byte STR header and 10h-byte Chunk header)
+ 018h - Nothing (total STR filesize is N*800h+18h bytes)
+
+Oldest Electronic Arts videos
+Wing Commander III: Heart of the Tiger (MOVIES1.LIB\*.wve) (1995, EA/Origin)
+ STR Sector Header:
+ No STR Sector header (first sector starts directly with "Ad10" chunk)
+ Video Chunks (MDEC):
+ 000h 4 Chunk ID "MDEC" ;\
+ 004h 4 Chunk Size (2xx0h) (big-endian) ;
+ 008h 2 Bitmap Width in pixels (big-endian) ; custom chunk header
+ 00Ah 2 Bitmap Height in pixels (big-endian) ;
+ 00Ch 2 Unknown (7FFFh) (big-endian) ;
+ 00Eh 2 Unknown (AD14h or AD24h) (big-endian) ;/
+ 010h .. Data (in BS v2 format) ;-standard BS v2 data
+ ... .. Padding, up to circa 20h bytes, FFh-filled
+ Audio Chunks (Ad10/Ad11) (22050Hz stereo):
+ 000h 4 Chunk ID ("ad20"=normal, "ad21"=last audio chunk)
+ 004h 4 Chunk Size (D38h or D28h) (or less in last chunk) (big-endian)
+ 010h .. SPU-ADPCM audio data, left ? (10h bytes per sample block)
+ ... .. SPU-ADPCM audio data, right ? (10h bytes per sample block)
+Audio seems to be 22050Hz stereo, however, chunks with size=D38h have odd
+amounts of sampleblocks, so it isn't as simple as having left/right in
+first/second half.
+
+Policenauts (Japan, 1996 Konami) (NAUTS\MOVIE\*.MOV)
+ STR Sector Header:
+ No STR Sector header (first sector starts directly with "VMNK" chunk)
+ First chunk (800h bytes):
+ 000h 4 ID "VMNK" (aka KNMV backwards, maybe for Konami Video/Movie)
+ 004h 4 Unknown (01h)
+ 008h 4 Unknown (01h)
+ 00Ch 4 Unknown (F0h)
+ 010h 4 Size of KLBS chunks? (40000h)
+ 014h 4 Bitmap X1 (aka left border)? (16pix, 10h)
+ 018h 4 Bitmap Y1 (aka upper border)? (16pix, 10h)
+ 01Ch 4 Bitmap Width (288pix, 120h)
+ 020h 4 Bitmap Height (144pix, 90h)
+ 024h 7E4h Zerofilled
+ Further chunks (40000h bytes, each):
+ 000h 8 Zerofilled
+ 008h 4 Chunk ID "KLBS" (aka SBLK backwards, maybe for Stream Block)
+ 00Ch 4 Chunk Size (usually 40000h)
+ 010h 4 Number of Name List entries
+ 014h 4 Number of Name List entries (same as above)
+ 018h 8 Zerofilled
+ 020h N*30h Name List
+ ... .. Data (referenced from Name List)
+ ... .. Zeropadding (to end of 40000h-byte chunk)
+The Name List does resemble a file archive, however, the "filenames" are just
+Type IDs (eg. all picture frames do have the same name).
+ Name List entries:
+ 000h 8 Zerofilled
+ 008h 8 Data Type Name (eg. "SCIPPDTS")
+ 010h 4 Time when to play/display the frame (0 and up)
+ 014h 4 Time duration for that frame (usually 14h for Picture frames)
+ 018h 4 Data Offset in bytes (from begin of chunk)
+ 01Ch 4 Data Size in bytes
+ 020h 10h Zerofilled
+Data Formats for the different Data Types...
+ Type "SDNSHDTS" aka SNDS,STDH - SoundStdHeader (Size=800h, Duration=0)
+ 000h 4 Maybe Pitch? (800h) (big-endian)
+ 004h 4 Maybe Pitch? (800h) (big-endian)
+ 008h 4 Total SPU-ADPCM size in bytes (for whole .MOV) (big-endian)
+ 00Ch 4 Unknown (FFFFFFFFh) (whatever)
+ 010h 4 Unknown (00007FFFh) (big-endian)
+ 014h 7ECh Zerofilled
+ Type "SDNSSDTS" aka SNDS,STDS - SoundStdStream (Size=10h..4000h, Duration=9Ch)
+ 000h 4000h SPU-ADPCM data in 10h-byte blocks (last chunk is less than 4000h)
+ Type "SCIPPDTS" aka PICS,STDP - PictureStdPicture (Size=3xxxh, Duration=14h)
+ 000h 3xxxh Picture Frame (in BS v1 format)
+ Type "SCTELLEC" aka ETCS,CELL - ExtraCells? (Size=0Ch, Duration=1)
+ 000h .. Maybe subtitle related...?
+ Type "SCTEGOLD" aka ETCS,DLOG - ExtraD-log? (Size=19h..31h, Duration=27h..44h)
+ 000h .. Maybe subtitle related...?
+Note: Total number of 10h-byte SPU-ADPCM blocks can be odd (so the audio seems
+to be mono).
+Apart from the .MOV files, there's also one standard .STR file for the Knnami
+Intro (with normal STR headers and BS v2 data).
+
+Best Sports Games Ever (DD\*.VLC and MOVIES\*.VLC) (Powerline Demo Disc menu)
+This format is used for still images with only frame, and for looping short
+animation sequences in the Demo Disc Menu. There's no audio.
+ Header Chunk:
+ 000h 4 Fixed ID (74h,55h,89h,08h aka 08895574h)
+ 004h 2 Bitmap Width (140h)
+ 006h 2 Bitmap Height (100h)
+ 008h 2 Video Frame Size/4 (17A0h or 13B0h)
+ 00Ah 2 Number of Video Frames (01h or 32h)
+ 00Ch 4 Frame End ID (eg. 62DCCACEh) (random?, but stays same within movie)
+ Video Frame Chunk(s):
+ ... .. Data (in BS v1/v2/v3 format) ;\size = hdr[008h]*4
+ ... .. FFh-filled (padding to Frame Size) ;/
+ ... 4 Frame End ID (eg. 62DCCACEh) ;-same value as in hdr[00Ch]
+For random access, best is seeking "fpos=N*(Framesize+4)+10h", alternately one
+could search "fpos=LocationAfterFrameEndID".
+
+Sentient (FILMS\*.FXA)
+This is having neither per-sector STR headers nor Chunk headers, instead it's
+having raw data with fixed size of 10 sectors per frame.
+File Header (sector 0, 800h bytes):
+ 000h 4 File ID (01h,"XSP") (aka PSX backwards)
+ 004h 2 Unknown (0001h)
+ 006h 2 Unknown (0040h) (this is used for something...)
+ 008h 2 Bitmap Width (0140h)
+ 00Ah 2 Bitmap Height (00F0h)
+ 00Ch 4 Total number of video frames
+ 010h 4 Number of video sectors per frame (always 8)
+ 014h 4 Total number of video sectors, excluding audio/dummy (=NumFrames*8)
+ 018h 1 Zero
+ 019h 1 Sector List size (28h) (ie. each 4 frames) ;\or zerofilled when
+ 01Ah 28h Sector Types (2=Video, 1=Audio, 0=Dummy) ;/not present
+ 042h .. Zerofilled
+ 7xxh .. Unknown, maybe just garbage ...?
+ ... .. Zerofilled
+The frame rate is 15fps with 10 sectors per frame (8xVideo and either 2xAudio
+or 1xAudio+1xDummy). The Video/Audio/Dummy sector arrangement does repeat each
+40 sectors (aka each 4 frames):
+ vVvvvvv--vvVvvv--vvvvVv--vvvvvv-Vvvvvvv- Video
+ -------A-------A-------A-------A-------A Audio
+ --------D-------D-------D--------------- Dummy
+ V = 1st sector of video frame
+ v = 2nd..8th sector of video frame (or fileheader in case of sector 0)
+ A = Audio (each 8th sector, ie. sector 07h,0Fh,17h,1Fh,etc.)
+ D = Dummy (occurs after some (not all) audio sectors)
+ Some files have that sector arrangement stored in header[019h..041h], but
+ other files have that header entries zerofilled (despite of using the same
+ arrangement).
+Video frames are 8 sectors (4000h-byte), first and last 8 bytes are swapped:
+ 0000h 8 Last 8 bytes of BS v1 bitstream ;\or garbage padding
+ 0008h 3FF0h First 3FF0h of BS v1 bitstream ;/
+ 3FF8h 8 Footer (64bit, with squeezed BS header and other info)
+ The footer bits are:
+ 0-4 5bit Quant (00h..1Fh) (only 5bit, not 6bit)
+ 5-15 11bit MDEC Size in 20h-word units (80h-byte units)
+ 16-23 8bit Unknown (lowbits are often same as bit48 and up?)
+ 24-31 8bit BS ID/100h (3800h/100h)
+ 32-47 16bit Frame Number (0=First)
+ 48-63 16bit Next Sector Number (start of next video frame)
+ To decrypt/convert the frame to standard BS v1 format:
+ x=[3FF8h] ;get footer
+ [3FF8h..3FFFh]=[0000h..0007h] ;last 8 bytes of bitstream
+ [0000h]=(x AND FF00FFE0h) ;size and ID=3800h
+ [0004h]=(x AND 1Fh)+10000h ;quant and version=v1
+ The next_sector number is usually current_sector+1 (or +2 if that would be
+ audio), in last frame it does point to end of file.
+ Bitstreams smaller than 3FF8h are garbage padded (initially some 32bit garbage
+ values, and in later frames leftovers from previous bitstream sectors).
+Dummy sectors contain 800h bytes:
+ 000h 4 Always FFFFFFFFh (unfortunately, this isn't a unique ID)
+ 004h 7FCh Garbage (zeroes, random, or even leaked ASM source code)
+ Dummy sectors have the same Subheader as video sectors, the leading FFFFFFFFh
+ could also occur in BS bitstreams or frames with garbage padding, so one must
+ use the sector arrangement pattern to identify dummy sectors.
+Audio sectors are XA-ADPCM and can be filtered via Subheader, or via sector
+arrangement pattern.
+
+CDROM File Video Streaming Mis-mastered files
+---------------------------------------------
+
+Mis-mastered streaming files
+There are several discs that have streaming data stored as partial CDROM images
+(instead of as real CDROM sectors).
+ Format Content Where
+ raw 920h-byte STR K9.5 1 - Live in Airedale (ZZBUFFER.STR) ;\
+ raw 920h-byte STR Need for Speed 3 (MOVIES\ZZZZZZZ*.PAD) ;
+ raw 920h-byte STR 3D Baseball (ZZZZZZZZ.ZZZ) ; intended
+ raw 920h-byte STR Wing Commander III (DUMMY.DAT) ; padding
+ raw 920h-byte STR R-Types (DMY\DUMMY.BIN) ;
+ raw 920h+junk STR+junk Grand Slam (DUMMY.BIN) ;
+ raw 920h-byte XA-ADPCM Spec Ops Airborne Commando (PADDING.NUL) ;
+ raw 920h-byte SW-STR Cyberia (ENDFILL\*.STR) (software render) ;
+ RIFFs/CDXAfmt STRs Sonic Wings Special (SW00.DMY = two RIFFs);/
+ raw 920h-byte XA-ADPCM Rugrats (MagDemo19: STREAMS\DB02.ISF) ;\nonsense
+ raw 920h-byte Data BABEh Rugrats (MagDemo19: STREAMS\OPEN.BIN) ; dupes
+ raw ???-byte CDDA Championship Surfer (MagDemo43: HWX\MUSIC);/
+ raw ???-byte CDDA Twisted Metal 2 (MagDemo50: TM2\FRWYSUB.DA) ;-?
+ raw 920h-byte STR Sonic Wings Special (MOV\MQ*.STR) ;-unused?
+ raw 920h-byte STR Apocalypse (MagDemo16: APOC\*.STR)
+ raw 920h-byte XA-ADPCM Apocalypse (MagDemo16: APOC\*.XA)
+ raw 920h-byte XA-ADPCM NFL Xtreme (MagDemo13: NFLX\GAME\SOUND\2PLAYRNO.XA)
+ raw 920h-byte XA-ADPCM Ace Combat 2 (MagDemo01: ACE2.STP)
+ raw 920h-byte XA-ADPCM Colony Wars (MagDemo02: CWARS\DEMO.PAK)
+ raw 920h-byte XA-ADPCM Best Sports demo (AH2\GAMEDATA\COM\MUSIC\MUSIC.IXA)
+ raw 920h-byte XA-ADPCM Tomb Raider: Last Revelation (MagDemo29: TR4\XA1.XA)
+ raw 800h-byte XA-ADPCM Croc 1 demo (MagDemo02: CROC\MAGMUS.STR) (FORM1)
+ RIFF/CDXAfmt XA-ADPCM Best Sports demo (LOMUDEMO\SFX\COMMENT.STR)
+ RIFF/CDXAfmt ?+XA-ADPCM Ace Combat 3 Electrosphere (MagDemo30: AC3\*.SPB)
+ RIFF/CDXAfmt XA-ADPCM Colony Wars Venegance (MagDemo14: CWV\SONYDEMO.PAK)
+ RIFF/WAVEfmt CDDA T'ai Fu (MagDemo16: TAIFU\3_10.WAV, 2x16bit 44100Hz)
+The 920h-byte sectors exclude the leading Sync mark and MM:SS:FF:Mode2 value.
+ Data/movie sectors look as so:
+ 000h 4 Sub-Header (File, Channel, Submode OR 20h, Codinginfo)
+ 004h 4 Copy of Sub-Header
+ 008h 800h Data (2048 bytes) ;<-- contains STR movie sectors
+ 808h 4 EDC (zerofilled)
+ 80Ch 114h ECC (zerofilled)
+ And XA-ADPCM sectors look as so:
+ 000h 4 Sub-Header (File, Channel, Submode OR 64h, Codinginfo)
+ 004h 4 Copy of Sub-Header
+ 008h 900h Data (18*128 bytes) ;\contains XA-ADPCM audio sectors
+ 908h 14h Data (zerofilled) ;/
+ 91Ch 4 EDC (zerofilled)
+The RIFF/CDXAfmt has a standard RIFF header, followed by 930h-byte sectors
+(same format as when opening CDROM streaming files in Windows). The
+RIFF/WAVEfmt is just a standard .WAV file.
+In case of the ZZ*.* files on retail discs, the developers did intentionally
+append some non-functional dummy STR files (instead of appending zerofilled
+30Mbyte at end of disc).
+--> CDROM File XYZ and Dummy/Null Files
+In case of the Demo Discs, the developers did probably have high hopes to
+release a demo version with working streaming data, just to find out that Sony
+had screwed up the data format (or maybe they had only accidentally included
+streaming data, without actually using it in demo version). Confusingly, the
+corrupted files were released on several discs (magazine demos, and other demo
+releases).
+The Rugrats demo has intact files in RUGRATS\CINEMAT and RUGRATS\XA folders,
+plus nonsense copies of that files in 920h-byte format in STREAMS folder.
+
+Partially mis-mastered files
+Legend of Dragoon (MagDemo34: LOD\XA\LODXA00.XA has FIRST SECTOR mis-mastered
+(it has TWO sub-headers (01,00,48,00,01,00,48,00,01,01,64,04,01,01,64,04), the
+remaining sectors are looking okay).
+
+Porsche Challenge (USA) (SRC\MENU\STREAM\*.STR)
+The subheader and data of the 1st sector are accidently overwritten by some
+ASCII string:
+ 000h 4 Subheader 01 44 2D 52 ".D-R" ;\distorted
+ 004h 4 Subheader copy 01 4D 20 47 ".M G" ;/"CD-ROM G"
+ 008h 299h Data ASCII 65 6E 65 72 61 ... "enerator for Windows"...
+ 2A1h 567h Data BS bitstream (but lacks BS header and start of bitstream)
+The 2nd sector and up are containing intact STR headers (for the 2nd-Nth sector
+of 1st frame, but the whole 1st frame is unusable due to missing 1st sector;
+however, the following frames are intact).
+
+CDROM File Video BS Compression Versions
+----------------------------------------
+
+STR/BS Version Summary, with popularity in percents (roughly)
+ Version .STR movies .BS pictures
+ BS v2 60% 6% Most games
+ BS v3 20% 4% Some newer games
+ BS v1 15% 0.1% Old games
+ BS ea 2% - (?) Electronic Arts titles
+ BS iki 0.5% 0.1% Several games
+ BS fraquant 0.2% 0.1% Rare (X-Files, Eagle One)
+ BS v0 0.1% - Rare (Serial Experiments Lain)
+ BS v2/v3.crypt 0.2% - Rare (Star Wars games)
+ BS iki.encrypted 0.1% - Rare (Panekit)
+ Wacwac MDEC 0.1% - Rare (Aconcagua)
+ Polygon Streams 0.x% (?) - Some titles
+ Raw MDEC - - Was never used in files?
+ MPEG1 - - VCD Video CDs
+ None ?% (?) 90% No videos or BS pictures
+Most games can decrypt v1/v2/v3 videos (no matter which of the three versions
+they are actually using), newer games do occassionally use v3 for picture
+compression, but often stick with v2 for video streaming (perhaps because v3
+does require slightly more CPU load; unknown if the higher CPU load has been an
+actual issue, and if it has been solved in the later (more optimized)
+decompressor versions) (unknown if there are other benefits like v2 having
+better DC quality or better compression in some cases?).
+
+BS v0 (used by only one known game)
+ v0 used by Serial Experiments Lain
+This game is apparently using a very old and very unoptimized decoder (although
+it was released in 1997, when most or all other games did already have decoders
+with v1/v2/v3 support).
+The v0 decoder has different header, lacks End of Frame codes, and uses Huffman
+codes with different AC values than v1/v2/v3/iki.
+
+BS v1 (used by older games, some of them also having v2 videos)
+ v1 used by Wipeout 2097 (MAKE.AV, XTRO*.AV)
+ v1 used by Viewpoint (MOVIES\*.STR) (oddly with [08h]=FirstFrame=0 and
+ [1Ch]=Unspecified=Nonzero) (the game also has ".str" files in
+ VIEW.DIR\streams, but that isn't MDEC/STR stuff)
+ v1 used by Ridge Racer Revolution (MOVIE\*.STR)
+ v1 used by Policenauts
+ v1 used by Final Fantasy VII (FF7)
+ v1? used by Tekken 2
+ v1/v2 used by Final Fantasy Tactics (OPEN*.STR)
+ v1/v2 used by Project Horned Owl (*.STR)
+ v1/v2 used by Gex (*.FMV)
+ (and probably more)
+v1 and v2 can be decoded with the same decompressor. The only difference is
+that v1 was generated with an older compressor (which did accidently store
+nonsense 22bit escape codes with run=N, level=0 in the bitstream; whereas one
+could as well use run+N+1 in the next code, or omit it completely if next code
+is EOB).
+
+BS v2 (most games)
+ v2 used by Gex - Enter the Gecko (*.STR)
+ v2 used by Tomb Raider (FMV\*.FMV)
+ v2 used by Alone (STR*\*.STR)
+ v2 used by Kain (*.STR)
+ v2 used by Fear Effect (BOOT.SID, LOGO.SID, ABGA\ABGA.FLX)
+ v2 used by Parasite Eve 2 (INTERx.STR, and in .CDF's eg. stage1\folder501)
+ v2 used by Witch of Salzburg (MOVIE\*.STR)
+ v2 used by Breath of Fire III (LOGO\*.STR)
+ v2 used by Hear it Now (MOVIE\*.STR)
+ v2 used by Legend of Mana (MOVIE\*.STR)
+ v2 used by Misadventures of Tron Bonne (STR\*.STR)
+ v2 used by Rayman (VIDEO\*.STR)
+ v2 used by Resident Evil 1 (PSX\MOVIE\*.STR) ;\although v3 is
+ v2 used by Resident Evil 2 (PL0\ZMOVIE\*.STR, ZMOVIE\*.STR) ;/used in *.BSS
+ v2 used by Tokimeki Memorial 2 (VX*.STR)
+ v2 used by Spider-Man (CINEMAS\*.STR)
+ v2 used by Perfect Assassin (CDV\*.STR)
+ v2 used by Pandemonium 2 (*.STR)
+ v2 used by Die Hard Trilogy 2 (MOVIE\*.STR)
+ v2 used by Need for Speed 3 (MOVIES\*.STR) (oddly with [14h,18h]<>[20h,24h])
+ v2 used by Wild Arms (STR\*.STR)
+ v2 used by Wild Arms 2 (STR\*.STR)
+ v2 used by Frogger (*.STR)
+ v2 used by Gundam Battle Assault (XA\*.STR)
+ v2 used by Alundra (MOVIE\*.MOV)
+ v2 used by Spec Ops (file 95h,96h within BIGFILE.CAT)
+ v2 used by Crash Team Racing (file 1E1h..1F8h,1FAh within BIGFILE.BIG)
+ (and many more)
+Same as v1, but without the compressor bug.
+
+BS v3 (used by some newer games, some of them also having v2 videos)
+ v2/v3 used by Lemmings Oh No More Lemmings (ANIMS\*.STR)
+ v2/v3 used by Castlevania (*.STR)
+ v3 used by Heart of Darkness (CINE\*.STR, SETUP\*.STR)
+ v3 used by R-Types (MV\*.STR)
+ v3 used by Black Matrix (MOVIE\*.STR)
+ v3 used by Nightmare Creatures II (INTRO\*.STR, LEVEL*\*.STR)
+ (and many more)
+Same as v2, but using Huffman compressed DC values.
+
+BS ea (Electronic Arts)
+Used by many EA Sports titles and several other titles from Electronic Arts:
+ Castrol Honda Superbike Racing
+ EA Sports Supercross 2000, 2001
+ Future Cop - L.A.P.D. (retail and MagDemo14: FCOPLAPD\*.WVE and *.FSV)
+ Hot Wheels - Turbo Racing
+ Jampack Vol. 2
+ Knockout Kings 99, 2000, 2001
+ Madden NFL 99, 2000, 2001, 2002, 2003, 2004, 2005 (eg. MADN00\FMVIDEO.DAT\*)
+ NASCAR 98, 99, 2000, 2001 (and 98 Collector's Edition, and 99 Legacy)
+ NASCAR Thunder 2002, 2003, 2004 and NASCAR Rumble
+ Nuclear Strike
+ Official U.S. PlayStation Magazine Demo Disc 39 (...XXX which game?)
+ PlayStation Underground Jampack - Winter 2000
+ Road Rash Jailbreak, and Road Rash 3D
+ Tiger Woods PGA Tour Golf, and Tiger Woods USA Tour 2001
+Uses VLC0 and MDEC chunks (instead of STR headers), the MDEC chunks contain
+standard BS v2 data, but using custom MDEC values from VLC0 chunk.
+
+BS fraquant
+ X-Files (Fox Interactive/Hyperbole Studios, 1999)
+ Eagle One: Harrier Attack (Infogrames/Glass Ghost, 2000)
+ Blue's Clues: Blue's Big Musical (Mattel/Viacom/TerraGlyph, 2000)
+This replaces the 6bit quant value by a 16bit fixed-point quant value (done by
+manipulating the Quant Table instead of using QuantDC, apart from that extra
+feature it's internally using normal BS v1/v2/v3 decoding).
+
+BS iki
+ iki: Gran Turismo 1 (STREAM.DAT) ;\with uncommon STR header
+ iki: Gran Turismo 2 (STREAM.DAT) ;/
+ iki: Hot Shots Golf 2 / Everybody's Golf 2 (MagDemo31: HSG2\MINGOL2X.BIN)
+ iki: Legend of Legaia (MagDemo20: LEGAIA\MOV\MV2.STR)
+ iki: Legend of Dragoon (STR\*.IKI)
+ iki: Omega Boost (MOVIE\*.IKI)
+ iki: Um Jammer Lammy (MagDemo24: UJL\*.IKI) (retail: *\*.IKI and CM\*.IK2)
+ iki: plus a dozen of japanese-only titles
+This might have been used between v2 and v3, iki is using uncommon BS headers
+and LZ compressed Quant/DC values (whilst v3 is using Huffman compressed DC
+values).
+
+Encrypted iki
+ Panekit - Infinitive Crafting Toy Case (first 13Mbyte in PANEKIT.STR)
+Same as normal iki, with some SWAP/ADD/XOR-encrytion in first 20h-bytes.
+
+Encrypted v2/v3
+ v3.xor used by Star Wars Masters of Teras Kasi (MagDemo03: MASTERS\*.STR)
+ v2.xor supported (but not actually used) by Star Wars Masters (MagDemo03)
+ v3.swap used by Star Wars Rebel Assault II (*.STR, *.SED, Stills)
+ v2.swap used by Star Wars Rebel Assault II (*.STR)
+ v3.swap used by BallBlazer Champions (*.STR)
+Same as normal v2/v3 with simple XOR-encryption or SWAP-encryption.
+
+Wacwac MDEC
+ Aconcagua (JP) (2000 Sony/WACWAC!) (STR_01_00.STR and STR_09_01.STR)
+Similar to v3, but uses completely different Huffman codes than BS video.
+
+Polygon Streaming (instead of MDEC picture streaming)
+ Ape Escape (DEMO\*.STR, STR\*.STR, and KKIIDDZZ.HED\STR\0006h and up)
+ Aconcagua (most STRs are Polygon Streams, except two are Wacwac MDEC streams)
+ Panekit - Infinitive Crafting Toy Case (last 150Mbyte in PANEKIT.STR)
+Polygon streams contain vertices (for textures that are stored elsewhere).
+Usually needing only one sector per frame. This can be useful for animations
+that were recorded from real actors. Drawbacks are more edgy graphics and lower
+color depth (although that may fit in with the game engine).
+--> CDROM File Video Polygon Streaming
+
+MPEG1 (on VCD Video CDs)
+MPEG1 uses I/P/B-Frames, the I-Frames may reach similar compression as BS
+files. However, P-Frames and B-Frames do compress much better than BS files.
+--> CDROM Video CDs (VCD)
+MPEG1 isn't used in any PSX games, but VCDs can be viewed on SCPH-5903 consoles
+(or via software decoder in nocash PSX kernel clone).
+
+Titles without movies
+Most PSX titles do include movies, exceptions are some early launch titles and
+educational titles:
+ Ridge Racer 1 (1994)
+ Lightspan Online Connection CD
+
+CDROM File Video BS Compression Headers
+---------------------------------------
+
+There are several different BS headers. The File ID/Version entries can be used
+to detect the correct type. The MDEC Size entry contains the size after Huffman
+decompression (ie. the half-decompressed size before passing the data to the
+MDEC decompression hardware) (usually divided by 4 and rounded up to 80h/4
+bytes).
+
+BS v1/v2/v3 header
+ 000h 2 MDEC Size/4 (after huffman decompression) (rounded to 80h/4 bytes)
+ 002h 2 File ID (3800h)
+ 004h 2 Quantization step/factor (0000h..003Fh, for MDEC "DCT.bit10-15")
+ 006h 2 Version (1, 2, or 3) (2 is most common)
+ 008h ... Huffman compressed data blocks (Cr,Cb,Y1,Y2,Y3,Y4, Cr,Cb,Y1,Y2..)
+
+Encrypted v2/v3
+Encryption is used in Star Wars games, there are two encryption schemes (XOR
+and SWAP).
+XOR-encrypt: Star Wars Masters of Teras Kasi (MagDemo03: MASTERS\*.STR):
+ 000h 2 MDEC Size/4 (rounded to 80h/4 bytes) (unencrypted) ;\same as normal
+ 002h 2 File ID (3800h) (unencrypted) ; BS v1/v2/v3
+ 004h 2 Quant (0..3Fh) (unencrypted) ;/
+ 006h 2 Version (in bit15, plus random in LSBs):
+ 00xxh..7FFFh for v2 (unknown if this could include values 0..3)
+ 8000h..FFFFh for v3 (bit14-0=random, varies in each frame)
+ 008h .. Encrypted bitstream
+ (each halfword XORed by BE67h for v2, or XORed by E67Bh for v3)
+ ... (2) Zeropadding to 4-byte boundary (unencrypted)
+ ... .. Zeropadding to end of sector (unencrypted)
+ The XOR values BE67h/E67Bh are hardcoded in the Star Wars Masters of Teras
+ Kasi .EXE (same XOR values for both retail and demo version), unknown if any
+ other games are also using that kind of encryption (and if yes, if they are
+ using the same XOR values).
+SWAP-encrypt: BallBlazer Champions, Star Wars Rebel Assault II (*.STR, *.SED):
+ 000h 2 MDEC Size/4 (rounded to 80h/4 bytes) ;\same as normal
+ 002h 2 File ID (3800h) ; BS v1/v2/v3
+ 004h 2 Quant (0..3Fh) ;/
+ 006h 2 Version (random 16bit, 00xxh..FFFFh) ;-no meaningful version info
+ 008h 2 Bitstream 2nd halfword ;\to "decrypt" the file,
+ 00Ah 2 Bitstream 1st halfword ;/these must be swapped
+ 00Ch .. Bitstream 3rd halfword and up ;-in normal order
+Whilst XORing or SWAPping the halfwords is simple, the more difficult part is
+distinguishing between SWAP-v2/v3 and XOR-v2/v3 encryption. This can be done as
+so:
+ if header[06h]<=0003h then assume unencrypted v0/v1/v2/v3
+ if header[06h]>=0004h then strip any trailing 0 bits, and check EndOfFrame..
+ if last 10bit = 0111111111 then assume SWAP.v2
+ if last 10bit = 1111111111 then assume SWAP.v3
+ otherwise assume XOR.v2/v3 (and use header[06h].bit15 to distinguish v2/v3)
+
+BS iki Header
+IKI videos have a custom .BS header, including some GT-ZIP compressed data:
+ 000h 2 MDEC Size/4 (rounded to 80h/4 bytes) ;\same as normal
+ 002h 2 File ID (3800h) ;/BS v1/v2/v3
+ 004h 2 Bitmap Width in pixels ;instead of Quant
+ 006h 2 Bitmap Height in pixels ;instead of Version
+ 008h 2 Size of GT-ZIP compressed data (plus 2-byte alignment padding)
+ 00Ah .. GT-ZIP compressed DC/Quant values (plus 2-byte alignment padding)
+ ... .. Huffman compressed AC data blocks (Cr,Cb,Y1,Y2,Y3,Y4, Cr,Cb,Y1,Y2..)
+The number of blocks is NumBlocks=(Width+15)/16*(height+15)/16*6. The size of
+the decompressed GT-ZIP data is NumBlocks*2.
+
+Encrypted iki
+The first 20h byte of the iki header & data are encrypted. Among others, the ID
+3800h is inverted (=C7FFh). To decrypt them:
+ [buf+00h]=[buf+00h] XOR FFFFFFFFh
+ [buf+04h] <--> [buf+08h] ;exchange 2x32bit
+ [buf+0Ch] <--> [buf+0Eh] ;exchange 2x16bit
+ [buf+10h]=[buf+10h]+FFFF6F7Bh
+ [buf+14h]=[buf+14h]+69140000h
+ [buf+18h]=[buf+18h]+FFFF7761h
+ [buf+1Ch]=[buf+1Ch]+6B040000h
+Note: The .STR header's StHeadM/StHeadV fields contain a copy of the decrypted
+values. The PANEKIT.STR file is 170Mbyte tall, but only the first 13Mbyte
+contain movie data... the rest is unknown stuff... often with zeroes followed
+by 7B,44,F0,29,E0,28 unknown what for...?
+
+BS fraquant
+ X-Files, GRAPHICS\*.STR,*.BIN, LOGOS\*.STR,*.BS
+ Eagle One: Harrier Attack (\*.STR, DATA*\*.STR) (leading zerofilled sectors)
+ Blue's Clues: Blue's Big Musical (*.STR) (has one leading zerofilled sector)
+This has a normal BS v1/v2/v3 header, with special quant entry:
+ 004h 2 Quant (0001h..0003h, or fixed-point 8000h..9xxxh)
+The decoder is using the default_quant_table (02h,10h,10h,13h,..,53h)
+multiplied with a fixed point number:
+ quant=BsHeader[04h] ;get fractional quant value
+ BsHeader[04h]=0001h ;force quant=1 (for use in BS v1/v2/v3 decoder)
+ if quant<8000h then quant=quant*200h else quant=quant AND 7FFFh
+ quant[0]=default_quant_table[0]
+ for i=1 to 3Fh,
+ x=(default_quant_table[i]*quant)/200h
+ if x=00000000h then quant[i]=01h else quant[i]=(x AND FFh)
+ next i
+ use MDEC(2) command to apply quant[0..3Fh] to both Luma and Chroma tables
+ use normal BS v1/v2/v3 decoder to decompress the bitmap
+BsHeader[04h] should be 0001h..0003h, or 8000h..862Bh (values outside that
+range would overflow the 8bit quant table entries). Values 0001h..0003h should
+should give same results as for normal BS decoding, so only values 8000h and up
+do need special decoding.
+Caution: Despite of the overflows, quant>862Bh is used (eg. X-Files
+GRAPHICS\GRAPHICS.BIN has quant=88C4h, Blue's Big Musical has quant=93E9h;
+those images do look okay, so the compressor seems to have recursed the
+overflows; or the overflow affects only a few pixels), however, very large with
+LSBs all zero (eg. 9000h) can cause 8bit table entries to become 00h (due to
+ANDing the result with FFh).
+Note: X-Files LOGOS\POP*.STR have quant=8001h (=near zero), that files are only
+60Kbyte and seem to be all black.
+Note: The movie engine uses COP2 GPF opcodes to calculate quant values.
+
+v0 Header (in STR files)
+ 000h 1 Quant for Y1,Y2,Y3,Y4 (00h..3Fh)
+ 001h 1 Quant for Cr,Cb (00h..3Fh)
+ 002h 2 File ID (3800h) (or Frame Number in ENDROLL1.STR on Disc 2)
+ 004h 2 MDEC Size/2 (!), and without padding (!) (unlike v1/v2/v3/iki)
+ 006h 2 BS Version (0) (actually MSBs of above Size, but it's always 0)
+ 008h .. Huffman Bitstream, first bit in bit7 of first byte
+
+v0 Header (in LAPKS.BIN chunks)
+LAPKS.BIN contains several chunks, each chunk contains an animation sequence
+with picture frame(s), each frame starts with following header:
+ 000h 2 Bitmap Width in pixels ;\cropped to non-black screen area,
+ 002h 2 Bitmap Height in pixels ;/size can vary within the sequence
+ 004h 2 Quant for Y1,Y2,Y3,Y4 (0000h..003Fh)
+ 006h 2 Quant for Cr,Cb (0000h..003Fh)
+ 008h 4 Size of compressed BS Bitstream plus 4 ;Transparency at [008h]+0Ch
+ 00Ch 2 Size/2 of MDEC data (after huffman decompression, without padding)
+ 00Eh 2 BS Version (0) (actually MSBs of above Size, but it's always 0)
+ 010h .. BS Bitstream with DC and AC values (Huffman compressed MDEC data)
+ ... 4 Transparency Mask Decompressed Size (Width*Height*2/8) (=2bpp)
+ ... .. Transparency Mask LZSS-compressed data
+For decompressing the transparency mask:
+--> CDROM File Compression LZSS (Serial Experiments Lain)
+The Transparency Mask is stored as scanlines (not as macroblocks), the
+upper/left pixel is in bit7-6 of first byte, the 2bit alpha values are ranging
+from 0=Transparent to 3=Solid.
+
+BS ea Headers (Electronic Arts)
+EA videos are chunk based (instead of using 20h-byte .STR headers).
+--> CDROM File Video Streaming Chunk-based formats
+VLC0 Chunk: Custom MDEC values (to be assigned to normal BS v2 Huffman codes).
+MDEC Chunks: Width/Height and BS v2 data (using MDEC values from VLC0 chunk).
+
+Raw MDEC
+There aren't any known pictures or movies in raw MDEC format. However, the
+Huffman decompression functions do usually output raw data in this format:
+ 000h 2 MDEC Size/4 (after huffman decompression) (rounded to 80h/4 bytes)
+ 002h 2 File ID (3800h)
+ 004h .. MDEC data (16bit DC/AC/EOB codes)
+ ... .. Padding (FE00h-filled to 80h-byte DMA transfer block size boundary)
+The first 4 bytes are the MDEC(1) command, the "ID" is always 3800h (equivalent
+to selecting 16bpp output; for 24bpp this must be changed to 3000h before
+passing the command to the MDEC hardware). The remaining bytes are MDEC data
+(padded to 80h-byte boundary).
+--> Macroblock Decoder (MDEC)
+
+CDROM File Video BS Compression DC Values
+-----------------------------------------
+
+DC v0
+ nnnnnnnnnn DC Value (signed 10bit, -200h..+1FFh)
+This is similar as v1/v2, except there is no End code for End of Frame, and the
+.BS header contains two separate quant values (for Cr/Cb and Y1-Y4).
+ If output_size=NumberOfMdecCodes*2 then EndOfFrame
+ If BlockIsCrCb then QuantDC=DC+QuantC*400h else QuantDC=DC+QuantY*400h
+
+DC v1/v2/ea
+ nnnnnnnnnn DC Value (signed 10bit, -200h..+1FEh)
+ 0111111111 End of Frame (+1FFh, that, in place of Cr)
+This is similar as v0, except there is only one Quant value for all blocks, and
+the header lacks info about the exact decompressed size, instead, compression
+end is indicated by a newly added end code:
+ If DC=+1FFh then EndOfFrame
+ QuantDC=DC+Quant*400h
+
+DC v3
+Similar as v1/v2, but DC values (and End code) are now Huffman compressed
+offsets relative to old DC, with different Huffman codes for Cr/Cb and Y1-Y4:
+ For Cr/Cb For Y1..Y4 Offset (added to old DC of Y/Cr/Cb block)
+ 00 100 +(00h) ;\
+ 01s 00s -(01h)*4 ,+(01h)*4 ;
+ 10sn 01sn -(03h..02h)*4,+(02h..03h)*4 ; required
+ 110snn 101snn -(07h..04h)*4,+(04h..07h)*4 ; codes
+ 1110snnn 110snnn -(0Fh..08h)*4,+(08h..0Fh)*4 ; for 10bit
+ 11110snnnn 1110snnnn -(1Fh..10h)*4,+(10h..1Fh)*4 ; range
+ 111110snnnnn 11110snnnnn -(3Fh..20h)*4,+(20h..3Fh)*4 ;
+ 1111110snnnnnn 111110snnnnnn -(7Fh..40h)*4,+(40h..7Fh)*4 ;/
+ 11111110snnnnnnn 1111110snnnnnnn -(FFh..80h)*4,+(80h..FFh)*4 ;-11bit (!)
+ - 11111110 Unused ;\
+ 111111110 111111110 Unused ; unused
+ 1111111110 1111111110 Unused ;/
+ 1111111111 1111111111 End of Frame ;-end code
+ Note: the "snnn" bits are indexing the values in right column,
+ with s=0 for negative values, and s=1 for positive values.
+The decoding works as so (with oldDcXxx=0 for first macroblock):
+ If bits=1111111111 then EndOfFrame
+ If BlockIsCr then DC=DecodeHuffman(HuffmanCodesCbCr)+oldDcCr, oldDcCr=DC
+ If BlockIsCb then DC=DecodeHuffman(HuffmanCodesCbCr)+oldDcCb, oldDcCb=DC
+ If BlockIsY1234 then DC=DecodeHuffman(HuffmanCodesY1234)+oldDcY, oldDcY=DC
+ If older_version AND DC>=0 then QuantDC=Quant*400h or (DC) ;\requires
+ If older_version AND DC<0 then QuantDC=Quant*400h or (DC+400h) ;/11bit
+ If newer_version then QuantDC=Quant*400h+(DC AND 3FFh) ;-wrap 10bit
+Note: The offsets do cover signed 11bit range -3FCh..+3FCh. Older v3 decoders
+did require 11bit offsets (eg. add +3FCh to change DC from -200h to +1FCh).
+Newer v3 decoders can wrap within 10bit (eg. add -4 to wrap DC from -200h to
++1FCh).
+
+DC iki
+The DC values (including Quant values for each block) are separately stored as
+GT-ZIP compressed data in the IKI .BS header.
+--> CDROM File Compression GT-ZIP (Gran Turismo 1 and 2)
+Calculate NumBlocks=(Width+15)/16*(height+15)/16*6, decompress the DC values
+(until DecompressedSize=NumBlocks*2). During Huffman decompression, read the DC
+values from the decompressed DC buffer (instead of from the Huffman bitstream):
+ If BlockNo>=NumBlocks then EndOfFrame
+ QuantDC = DCbuf[BlockNo]*100h + DCbuf[BlockNo+NumBlocks]
+As shown above, the Hi- and Lo-bytes are stored in separate halves of the DC
+buffer (which may gain better compression).
+
+CDROM File Video BS Compression AC Values
+-----------------------------------------
+
+Below shows the huffman codes and corresponding 16bit MDEC values; the "xx"
+bits contain an index in the list of 16bit MDEC values, the "s" bit means to
+negate the AC level (in lower 10bit of the 16bit MDEC value) when s=1.
+
+Huffman codes for AC values BS v1/v2/v3/iki
+ 10 FE00h ;End of Block, EOB
+ 11s 0001h
+ 011s 0401h
+ 010xs 0002h,0801h
+ 0011xs 1001h,0C01h
+ 00101s 0003h
+ 00100xxxs 3401h,0006h,3001h,2C01h,0C02h,0403h,0005h,2801h
+ 0001xxs 1C01h,1801h,0402h,1401h
+ 00001xxs 0802h,2401h,0004h,2001h
+ 000001xxxxxxxxxxxxxxxx 0000h..FFFFh ;Escape code for raw 16bit values
+ 000001xxxxxx0000000000 0000h..FC00h ;Escape nonsense level=0 (used in v1)
+ 0000001xxxs 4001h,1402h,0007h,0803h,0404h,3C01h,3801h,1002h
+ 00000001xxxxs 000Bh,2002h,1003h,000Ah,0804h,1C02h,5401h,5001h,
+ 0009h,4C01h,4801h,0405h,0C03h,0008h,1802h,4401h
+ 000000001xxxxs 2802h,2402h,1403h,0C04h,0805h,0407h,0406h,000Fh,
+ 000Eh,000Dh,000Ch,6801h,6401h,6001h,5C01h,5801h
+ 0000000001xxxxs 001Fh,001Eh,001Dh,001Ch,001Bh,001Ah,0019h,0018h,
+ 0017h,0016h,0015h,0014h,0013h,0012h,0011h,0010h
+ 00000000001xxxxs 0028h,0027h,0026h,0025h,0024h,0023h,0022h,0021h,
+ 0020h,040Eh,040Dh,040Ch,040Bh,040Ah,0409h,0408h
+ 000000000001xxxxs 0412h,0411h,0410h,040Fh,1803h,4002h,3C02h,3802h,
+ 3402h,3002h,2C02h,7C01h,7801h,7401h,7001h,6C01h
+ 000000000000 Unused
+
+Huffman codes for AC values BS v0 (Serial Experiments Lain)
+ 10 FE00h ;End of Block, EOB
+ 11s 0001h
+ 011s 0002h
+ 010xs 0401h,0003h
+ 0011xs 0801h,0005h
+ 00101s 0004h
+ 00100xxxs 000Ah,000Bh,0403h,1801h,000Ch,000Dh,1C01h,000Eh
+ 0001xxs 0006h,0C01h,0402h,0007h
+ 00001xxs 0008h,1001h,0009h,1401h
+ 000001xxxxxx0xxxxxxx 0000h..FC00h+(+001h..+07Fh AND 3FFh) ;\
+ 000001xxxxxx000000001xxxxxxx 0000h..FC00h+(+080h..+0FFh AND 3FFh) ; Escape
+ 000001xxxxxx000000000xxxxxxx Unused ; codes
+ 000001xxxxxx1xxxxxxx 0000h..FC00h+(-080h..-001h AND 3FFh) ;
+ 000001xxxxxx100000000xxxxxxx 0000h..FC00h+(-100h..-081h AND 3FFh) ;
+ 000001xxxxxx100000001xxxxxxx Unused ;/
+ 0000001xxxs 000Fh,0802h,2001h,0404h,0010h,0011h,2401h,0012h
+ 00000001xxxxs 0013h,0405h,0014h,2801h,0015h,0C02h,3001h,0017h,
+ 0016h,2C01h,0018h,001Ch,0019h,0406h,0803h,001Bh
+ 000000001xxxxs 001Ah,3401h,001Dh,0407h,1002h,001Fh,001Eh,3801h,
+ 0020h,0021h,0408h,0023h,0022h,1402h,0024h,0025h
+ 0000000001xxxxs 0804h,0409h,0418h,0026h,3C01h,0027h,0C03h,1C03h,
+ 0028h,0029h,002Ah,002Bh,040Ah,002Ch,1802h,002Dh
+ 00000000001xxxxs 002Fh,002Eh,4001h,0805h,0030h,040Bh,0031h,0033h,
+ 0032h,1C02h,0034h,1003h,0035h,4401h,040Ch,0037h
+ 000000000001xxxxs 0036h,0038h,0039h,5401h,003Ah,0C04h,040Dh,5C01h,
+ 2002h,003Bh,0806h,4C01h,003Ch,2402h,6001h,4801h
+ 000000000000 Unused
+Uses different 16bit MDEC values, and the Escape code is different: 8bit levels
+are 2bit shorter than v1/v2/v3, but 9bit levels are much longer, and 10bit
+levels are not supported at all (those v0 Escape codes are described in Sony's
+File Format documented; albeit accidentally because the doc was actually trying
+to describe v2/v3).
+
+Huffman codes for AC values BS ea (Electronic Arts)
+This is using custom MDEC values from VLC0 chunk, and assigns them to the
+standard Huffman codes. There are two special MDEC values:
+ FE00h End of Block (EOB)
+ 7C1Fh Escape code (huffman code will be followed by v2-style 16bit value)
+VLC0 chunk entries 00h..DFh are mapped to the following Huffman codes:
+ 10 00
+ 11x 01,02
+ 011x 03,04
+ 010xx 05,06,07,08
+ 0011xx 0D,0E,0B,0C
+ 00101x 09,0A
+ 00100xxxx 2E,2F,22,23,2C,2D,2A,2B,26,27,24,25,20,21,28,29
+ 0001xxx 15,16,13,14,0F,10,11,12
+ 00001xxx 1A,1B,1E,1F,18,19,1C,1D
+ 000001 17h
+ 0000001xxxx 3E,3F,38,39,30,31,34,35,32,33,3C,3D,3A,3B,36,37
+ 00000001xxxxx 46,47,54,55,4E,4F,44,45,4A,4B,52,53,5E,5F,5C,5D,
+ 42,43,5A,5B,58,59,48,49,4C,4D,40,41,50,51,56,57
+ 000000001xxxxx 74,75,72,73,70,71,6E,6F,6C,6D,6A,6B,68,69,66,67,
+ 64,65,62,63,60,61,7E,7F,7C,7D,7A,7B,78,79,76,77
+ 0000000001xxxxx 9E,9F,9C,9D,9A,9B,98,99,96,97,94,95,92,93,90,91,
+ 8E,8F,8C,8D,8A,8B,88,89,86,87,84,85,82,83,80,81
+ 00000000001xxxxx B0,B1,AE,AF,AC,AD,AA,AB,A8,A9,A6,A7,A4,A5,A2,A3,
+ A0,A1,BE,BF,BC,BD,BA,BB,B8,B9,B6,B7,B4,B5,B2,B3
+ 000000000001xxxxx C6,C7,C4,C5,C2,C3,C0,C1,C8,C9,D4,D5,D2,D3,D0,D1,
+ CE,CF,CC,CD,CA,CB,DE,DF,DC,DD,DA,DB,D8,D9,D6,D7
+ 000000000000 Unused
+All codes can be freely assigned (Escape and EOB don't need to be at 10 and
+000001, and the last huffman bit doesn't have to serve as sign bit).
+
+Notes
+All BS versions are using the same Huffman codes (the different BS versions do
+just assign different 16bit MDEC codes to them).
+The huffman codes can be neatly decoded by "counting leading zeroes" (without
+needing bitwise node-by-node processing; this is done in IKI video decoders via
+GTE registers LZCS and LZCR). Sony's normal v2/v3 decoders are using a yet
+faster method: A large table to interprete the next 13bit of the bitstream, the
+table lookup can decode up to 3 huffman codes at once (if the 13bit contain
+several small huffman codes).
+
+CDROM File Video BS Picture Files
+---------------------------------
+
+BS Picture Files
+A couple of games are storing single pictures in .BS files:
+ Alice in Cyberland (ALICE.PAC\*.BS)
+ BallBlazer Champions (BBX_EXTR.DAT\Pics\*) (SWAP-encrypted)
+ Bugriders: The Race of Kings (*\*.BS and STILLS\MENUS.BS\*)
+ Die Hard Trilogy 2 (DATA\*.DHB, DATA\DH*\L*\*.DHB, MOVIE\*.DHB)
+ Dino Crisis 2 (PSX\DATA\ST*.DBS\*)
+ Duke Nukem (MagDemo12: DN_TTK\*)
+ Final Fantasy VII (FF7) (MOVIE\FSHIP2*.BIN\*) (BS v1)
+ Gran Turismo 1 (retail TITLE.DAT\* and MagDemo10/15) (in BS iki format)
+ Jet Moto 2 (MagDemo03: JETMOTO2\*)
+ Mary-Kate and Ashley Crush Course (MagDemo52: CRUSH\SCRN\*.BS)
+ Mat Hoffman's Pro BMX (MagDemo48: MHPB\STILLS.BIN\*) (with width/height info)
+ NFL Gameday '99 (MagDemo17: GAMEDAY\FE\GD98DATA.DAT)
+ Official U.S. PlayStation Magazine Demo Disc 01-02 (MENU\DATA\*.BSS)
+ Official U.S. PlayStation Magazine Demo Disc 03-54 (MENU.FF\*)
+ Parasite Eve 2 (INIT.BS, and within .HED/.CDF archives)
+ Resident Evil 1 (PSX\STAGE*\*.BSS, headerless archive, 8000h-byte align)
+ Resident Evil 2 (COMMON\BSS\*.BSS, headerless archive, 10000h-byte align)
+ Rugrats (MagDemo19: RUGRATS\*)
+ Rugrats Studio Tour (MagDemo32: RUGRATS\DATA\RAW\*.BS)
+ Starwars Demolition (MagDemo39+MagDemo41: STARWARS\SHELL\.BS+.TBL\*)
+ Star Wars Rebel Assault 2 (RESOURCE.000\Stills\*) (SWAP-encrypted)
+ Ultimate Fighting Championship (MagDemo38: UFC\CU00.RBB\390h..3E2h)
+ Vigilante 8 (MagDemo09: EXAMPLE\*)
+ Witch of Salzburg (PICT\PIC*\*.BS and DOT1 archives *.BSS, *.DAT, *.BIN)
+ X-Files (LOGOS\*.BS and GRAPHICS\GRAPHICS.BIN and GRAPHICS\PACKEDBS.BIN\*)
+ You Don't Know Jack 2 (MagDemo41: YDKJV2\RES\UI\*.BS)
+Note: Those .BS files are usually hidden in custom file archives.
+
+BS Picture Resolution
+Movies have Width/Height entries (in the .STR header). Raw .BS picture files
+don't have any such information. However, there are ways to guess the correct
+resolution:
+ For BS iki format, use resolution from iki header (eg. Gran Turismo 1)
+ For MHPB\STILLS.BIN, there's width/height in chunk headers
+ Count the number of blocks (EOB codes) during Huffman decompression
+ Divide that number by 6 to get the number of Macroblocks
+ Search matches for Height=NumBlocks/Width with Width>=Height and Remainder=0
+ If Height=300..400, assume double H-resolution, repeat with Width/2>=Height
+ And/or use a list of known common resoltions (see below examples)
+ Search arrangements with many similar colors on adjacent macroblocks
+Common resolutions are:
+ Blocks Pixels Example
+ F0h 256x240 any?
+ 12Ch 320x240 Resident Evil 2 (COMMON\BSS\*.BSS)
+ 1E0h 512x240 Demo Disc 03-54 (MENU.FF\*), Duke Nukem (MagDemo12)
+ 1E0h 640x192 Less common than above (but used by Witch of Salzburg)
+ 4B0h 640x480 Vigilante 8 (MagDemo09), Jet Moto 2 (MagDemo03)
+ var random Witch of Salzburg has various random resolutions
+ iki ikihdr Gran Turismo 1 has A0hxA0h and odd size (!) E8hx28h
+ ? ? Final Fantasy VII (FF7)
+ ? ? Ultimate Fighting Championship (UFC\CU00.RBB\3B7h..3E2h)
+ 118h 320x224 Alice in Cyberland (most files; or two such as panorama)
+ 230h ? Alice in Cyberland (AD_115.BS and AD_123A.BS)
+Some other possible, but rather unlikely results would be:
+ C8h 320x160 Unlikely for pictures (but used for STR videos, eg. Alone)
+ F0h 320x192 Unlikely for pictures (but used for STR videos, eg. Wipeout)
+ 1E0h 384x320 Very unlikely to see that vertical resolution on PSX
+Witch of Salzburg has many small .BS files with various uncommon resolutions
+(most of them are bundled with 16-byte .TXT files with resolution info).
+
+Extended BS with Width/Height
+Starwars Demolition (MagDemo39: STARWARS\SHELL\DEMOLOGO.BS+RESOURCE.TBL\*)
+Starwars Demolition (MagDemo41: STARWARS\SHELL\DEMOLOGO.BS+RESOURCE.TBL\*)
+ 000h 2 Width (280h) ;\extra header
+ 002h 2 Height (1E0h) ;/
+ 004h 2 MDEC Size/4 (after huffman decompression) (rounded to 80h/4 bytes)
+ 006h 2 File ID (3800h)
+ 008h 2 Quantization step/factor (0000h..003Fh, for MDEC "DCT.bit10-15")
+ 00Ah 2 Version (1, 2, or 3) (2 is most common)
+ 00Ch ... Huffman compressed data blocks (Cr,Cb,Y1,Y2,Y3,Y4, Cr,Cb,Y1,Y2..)
+
+CDROM File Video Wacwac MDEC Streams
+------------------------------------
+
+Wacwac uses different Huffman codes than BS videos, the decoder has some
+promising ideas that might yield slightly better compression than BS v3.
+However, it is used by only one known game:
+ Aconcagua (JP) (2000 Sony/WACWAC!)
+And even that game is only using it in two movies, and the movies are barely
+making any use of it: The 20Mbyte intro scene is a picture slide show (where
+the camera is zooming across twelve black and white images), the 50Mbyte ending
+scene is providing a more cinematic experience (the camera is scrolling through
+a text file with developer staff names).
+
+Wacwac MDEC Stream Sectors
+ 000h 2 STR ID (0160h)
+ 002h 2 STR Type WACWAC Tables (0002h=IntroTableSet, 0003h=EndingTableSet)
+ 004h 2 Sector number within current Frame (0000h..num-1)
+ 006h 2 Number of Sectors in this Frame
+ 008h 4 Frame number (6 or 11 and up, because 1st some frames are Polygons)
+ 00Ch 4 Frame Size in bytes
+ 010h 2 Bitmap Width (always 140h) ;\always 320x208 (in fact, the
+ 012h 2 Bitmap Height (always 0D0h) ;/decoder is hardcoded as so)
+ 014h 4 Quant (0..3Fh) (same for all sectors within the frame)
+ 018h 8 Zerofilled
+ 020h 7E0h Raw Bitstream data (without Quant or BS header) (garbage padded)
+Aconcagua has dozens of STR files with Polygon Streams. MDEC Streams are found
+only in two STR files for Intro and Ending scenes:
+ Intro=Disc1:\ST01_01\STR_01_00.STR Ending=Disc2:\ST09_01\STR_09_01.STR
+ Leading zeroes (150 sectors) Leading zeroes (150 sectors)
+ Frame 0001h..0005h Polygon Frames Frame 0001h..000Ah Polygon Frames
+ Frame 0006h..0545h MDEC Frames 20MB Frame 000Bh..0D79h MDEC Frames 50MB
+ Frame 0546h..1874h Polygon Frames 48MB
+Audio is normal XA-ADPCM, with the first audio sector occuring before 1st frame
+(after the leading zeropadded 150 sectors).
+
+Wacwac Huffman Bitstreams
+Wacwac uses little-endian bitstreams (starting with low bit in bit0 of first
+byte). To decode the separate blocks in the bitstream:
+ Read Huffman code for DC, and output Quant*400h+(DC AND 3FFh)
+ Read Huffman code for Size, aka num1,num2,num3 values for below reads
+ Repeat num1 times: Read Huffman code for AC1, and output AC
+ Repeat num2 times: Read Huffman code for AC2, and output AC
+ Repeat num3 times: Read Huffman code for AC3, and output AC
+ Output EOB (end of block)
+The header/data lacks info about MDEC size after Huffman decompression, the
+worst case size for 320x208pix would be:
+ 14h*0Dh*6*41h*2+Align(80h)+Header(4) = 31880h+4 bytes
+Note: The bitstream consists of separate 16x208pix slices (set DC for Cr,Cb,Y
+to zero at begin of each slice, and skip padding to 32bit-boundary at end of
+each slice).
+
+Wacwac Huffman Table Sets
+Aconcagua has two table sets, stored in PROGRAM.BIN (in compressed form,
+appearing as so: FF,90,16,2E,06,20,03,D6,etc). While watching the intro movie,
+the uncompressed sets can be found at these RAM locations:
+ 80112AF8h (1690h bytes) ;Table Set for Intro Scene
+ 80114188h (1B68h bytes) ;Table Set for Ending Scene
+Each Table Set has a 38h-byte header, followed by five tables:
+ 000h 4 Table Set size (1690h or 1B68h)
+ 004h 4 Table Set exploded size (when allocating 16bit/DC, 32bit/Size/AC)
+ 008h 2 Size Table max Huffman size in bits (0Ah or 09h) ;\Size
+ 00Ah 2 Size Table number of entries (40h) ;/
+ 00Ch 2 DC Table max Huffman size in bits (0Bh) ;\
+ 00Eh 2 DC Table number of entries (100h) ; DC
+ 010h 2 DC Huffman code Escape 10bit (non-relative 10bit DC value) ;
+ 012h 2 DC Huffman size Escape 10bit (3 or 6, escape prefix size) ;/
+ 014h 2 AC1 Table max Huffman size in bits (0Eh or 0Bh) ;\
+ 016h 2 AC1 Table number of entries (0DAh or 100h) ;
+ 018h 2 AC1 Huffman code Escape 7bit (run=0bit, level=signed7bit) ; AC1
+ 01Ah 2 AC1 Huffman code Escape 16bit (run=6bit, level=10bit) ;
+ 01Ch 2 AC1 Huffman size Escape 7bit (9 or 7, escape prefix size) ;
+ 01Eh 2 AC1 Huffman size Escape 16bit (9 or 7, escape prefix size) ;/
+ 020h 2 AC2 Table max Huffman size in bits (0Eh) ;\
+ 022h 2 AC2 Table number of entries (AAh or F4h) ;
+ 024h 2 AC2 Huffman code Escape 8bit (run=3bit, level=signed5bit) ; AC2
+ 026h 2 AC2 Huffman code Escape 16bit (run=6bit, level=10bit) ;
+ 028h 2 AC2 Huffman size Escape 8bit (10 or 9, escape prefix size) ;
+ 02Ah 2 AC2 Huffman size Escape 16bit (10 or 9, escape prefix size) ;/
+ 02Ch 2 AC3 Table max Huffman size in bits (0Eh) ;\
+ 02Eh 2 AC3 Table number of entries (87h or B2h) ;
+ 030h 2 AC3 Huffman code Escape 8bit (run=4bit, level=signed4bit) ; AC3
+ 032h 2 AC3 Huffman code Escape 16bit (run=6bit, level=10bit) ;
+ 034h 2 AC3 Huffman size Escape 8bit (10 or 9, escape prefix size) ;
+ 036h 2 AC3 Huffman size Escape 16bit (10 or 9, escape prefix size) ;/
+ 038h .. Size Table (64bit per entry) ;\
+ ... .. DC Table (32bit per entry) ;
+ ... .. AC1 Table (64bit per entry) ; Tables
+ ... .. AC2 Table (64bit per entry) ;
+ ... .. AC3 Table (64bit per entry) ;/
+Size Table entries (64bit):
+ 0-1 Zero
+ 2-31 Huffman code (10bit max)
+ 32-39 Number of AC1 codes in this block ;\implies End of Block (EOB)
+ 40-47 Number of AC2 codes in this block ; after those AC codes
+ 48-55 Number of AC3 codes in this block ;/
+ 56-63 Huffman size (1..10 bits)
+DC Table entries (32bit):
+ 0-9 Relative DC Value (relative to old DC from memorized Cr,Cb,Y)
+ 10-15 Huffman size (1..11 bits)
+ 16-31 Huffman code (11bit max)
+ Notes: For the relative DC's, the decoder does memorize DC for Cr,Cb,Y upon
+ decoding Cr,Cb,Y1,Y3 (but does NOT memorize DC when decoding Y2,Y4).
+ Initial DC for Cr,Cb,Y is zero at begin of each 16x208pix slice.
+ Obscurities: The decoder does accidentally use bit10 to sign-expand the
+ DC value in bit0-9 (but does mask-off those bugged sign bits thereafter),
+ and the decoder does uselessly memorize Y1 and Y3 separately (but uses only
+ the most recently memorized value).
+AC1/AC2/AC3 Table entries (64bit):
+ 0-1 Zero
+ 2-31 Huffman code (14bit max)
+ 32-47 MDEC code (6bit run, and 10bit AC level)
+ 48-63 Huffman size (1..14 bits)
+The Escape codes are stored in the 38h-byte Table Set header (instead of in the
+tables), the init function uses that info for patching escape-related opcodes
+in the decoder function (that would allow to omit table lookups upon escape
+codes; the decoder doesn't actually omit such lookups though).
+To simplify things, one could store the escape codes in the tables (eg. using
+special MDEC values like FC00h+35h for run=3bit, level=signed5bit).
+
+CDROM File Video Polygon Streaming
+----------------------------------
+
+Ape Escape - Polygon Streaming
+Used by Ape Escape (Sony 1999) (DEMO\*.STR and some STR\*.STR files and
+KKIIDDZZ.HED\STR\0006h and up).
+The files start with zerofilled sectors (without STR headers), followed by
+sectors with STR headers with [00h]=0160h, [02h]=8001h (same values as for
+MDEC), but with [10h..1Fh]=zero (without resolution/header info). And the data
+at [20h] starts with something like 14h,00h,03h,FFh,2Ah,02h,00h,00h.
+That data seems to consist of polygon coordinates/attributes that are rendered
+as movie frames. The texture seems to be stored elsewhere (maybe in the .ALL
+files that are bundled with some .STR files).
+
+Panekit - Polygon Streaming
+Panekit STR seems to use Polygon Streaming (except 1st some Megabytes are
+MDEC).
+
+Aconcagua - Polygon Streaming
+Aconcagua STR does use Polygon Streaming (except first+last movie are MDEC).
+
+Cyberia (1996) (TF\STR\*.STR)
+Cyberia is using Software-rendering for both movies and in-game graphics. That
+is, PSX hardware features like MDEC, GTE, and GPU-Polygons are left all unused,
+and the GPU is barely used for transferring data from CPU to VRAM.
+The STR header for software-rendered movie frames looks as so:
+ 000h 2 STR ID (0160h)
+ 002h 2 STR Type (0002h=Custom, Software rendering)
+ 004h 2 Sector number within current Frame (0..num-1)
+ 006h 2 Number of Sectors in this Frame (varies)
+ 008h 4 Frame Number (1=First)
+ 00Ch 4 Frame Size in Bytes/4 (note: first frame in MAP*.STR is quite big)
+ 010h 2 Rendering Width (0140h)
+ 012h 2 Rendering Height (00C0h)
+ 014h 0Ch Unknown (zerofilled or random garbage)
+ 020h 7E0h Custom data for software rendering
+Note: First sector of First frame does usually have byte[22h]=88h (except
+FINMUS.STR). The Custom data part is often have garbage padding (such like
+ASCII strings with "c2str" command line tool usage instructions).
+
+Croc 1 (CUTS\*.AN2)
+Probably cut-scenes with polygon animations. The files seem to contain
+2300h-byte data frames (plus XA-ADPCM sectors inserted here and there).
+ 000h 4 Number of remaining frames
+ ... 22FCh Unknown data (zeropadded if smaller)
+
+ _______________ Unknown Streaming Data (Polygons or whatever) ________________
+
+Custom STR - 3D Baseball (BIGFILE.FOO)
+This is used for several files in 3D Baseball (BIGFILE.FOO):
+ BIGFILE.FOO\0151h\0005h,0009h,000Fh,0017h,001Bh, 02E5h,02E9h,..,0344h,0348h
+ BIGFILE.FOO\0152h\0186h,018Ch,0192h,0198h)
+ BIGFILE.FOO\0153h\029Ah,02A0h,02A6h,02ACh)
+The files contain some kind of custom streaming data, with custom STR header,
+and data containing increasing/decreasing bytes... maybe non-audio waveforms?
+ 000h 2 STR ID (0160h)
+ 002h 2 STR Type (0001h=Custom)
+ 004h 2 Sector number within current Frame (always 0)
+ 006h 2 Number of Sectors in this Frame (always 1)
+ 008h 4 Frame Number (1=First)
+ 00Ch 4 Frame Size (6FAh or 77Ah, sometimes 17Ah or 1FAh or 20Ah)
+ 010h 2 Unknown (280h, or sometimes 300h or 340h)
+ 012h 2 Frame Time (0=First, increases with step [19h], usually +5 or +7)
+ 014h 2 Unknown (280h, or sometimes 300h or 3C0h, or 0)
+ 016h 1 Frame Time (same as [012h] AND FFh)
+ 017h 1 Unknown (0 or 1)
+ 018h 1 Unknown (40h, or 80h, or C0h)
+ 019h 1 Duration? (5 or 7, or sometimes less, step for Frame Time)
+ 01Ah 1 Unknown (3, or less in last some frames)
+ 01Bh 5 Zerofilled
+ 020h 7E0h Data (increasing/decreasing bytes... maybe non-audio waveforms?)
+
+Army Men Air Attack 2 (MagDemo40: AMAA2\*.PMB)
+ 000h 2 STR ID (0160h)
+ 002h 2 STR Type (0000h=Custom)
+ 004h 2 Sector number within current Frame (0..2)
+ 006h 2 Number of Sectors in this Frame (always 4) (3xSTR + 1xADPCM)
+ 008h 4 Frame Number (1=First)
+ 00Ch 4 Frame Size? (800h, despite of having 3 sectors with 7E0h each?)
+ 010h 2 Unknown (00h or 01h)
+ 012h 2 Unknown (A3h or ABh ... 6Ch or 7Bh ... or 43h or 49h)
+ 014h 2 Sector number within current Frame (0..2) (same as [004h])
+ 016h 0Ah Zerofilled
+ 020h 7E0h Data (polygon streaming or so?)
+Note: The .PMB file is bundled with a .PMH file, which might contain header
+info?
+
+Bits Laboratory games (Charumera, and True Love Story series)
+ Charumera ENDING.XA (with dummy/zero data)
+ True Love Story TLS\MULTI.XA (with nonzero data)
+ True Love Story 2 TLS2\ENDING.STR and TLS2\MULTI.XA
+ True Love Story Fan Disc ;\probably use that format, too
+ True Love Story: Remember My Heart ;/(not verified)
+The STR headers have STR ID=0160h and STR Type=0001h, STR header[10h..1Fh]
+contains nonsense BS video info (with BS ID=3800h, although there isn't any BS
+data in the actual data part at offset 20h and up).
+The files do mainly contain XA-ADPCM sectors, plus some STR sectors in non-MDEC
+format. Unknown if that STR sectors are separate channels, or if they are used
+in parallel with the XA-ADPCM channel(s).
+Unknown what the STR sectors are used for (perhaps Polygon Streaming, audio
+subtitles, or simple garbage padding for unused audio sectors). In some files,
+the STR sectors appear to be just dummy padding (STR header plus zerofilled
+data area).
+
+Nightmare Project: Yakata
+This game has normal MDEC Streams, and Special Streams in non-MDEC format (eg.
+Disc1, File 0E9h-16Eh and 985h-B58h), perhaps containing Polygon Streams or
+whatever.
+There are two channels (file=1/channel=00h-01h), each channel contains data
+that consists of 5 sectors per frame (1xHeader plus 4xData). The sectors have
+STR ID=0160h, and STR Type as follows:
+ 0000h=Whatever special, channel 0 header (sector 0)
+ 0400h=Whatever special, channel 1 header (sector 1)
+ 0001h=Whatever special, channel 0 data (sector 2,4,6,8)
+ 0401h=Whatever special, channel 1 data (sector 3,5,7,9)
+
+Eagle One: Harrier Attack STR files
+ \*.STR MDEC movies ;\BS fraquant (except, demo version
+ \DATA*\*.STR MDEC movies ;/ on MagDemo31 uses mormal BS v2)
+ \DATA*\M*\L*.STR Multi-language TXT files with STR header on each sector
+ \DATA*\M*\I*.STR unknown binary data (whatever and SPU-ADPCM)
+ \LANGN.STR unknown binary data (whatever)
+All of the above have STR Type=8001h (but only the MDEC movies have BS ID
+3800h; the MDEC movies start with 13 zerofilled sectors that are all zeroes
+without any STR/BS headers).
+
+CDROM File Audio Single Samples VAG (Sony)
+------------------------------------------
+
+VAG audio samples
+PSX Lightspan Online Connection CD, cdrom:\CD.TOC:\UI*\*.VAG
+PSX Wipeout 2097, cdrom:\WIPEOUT2\SOUND\SAMPLES.WAD:\*.vag (version=02h)
+PSX Perfect Assassin, DATA.JFS:\AUDIO\*.VAG and DATA.JFS:\SND\*.VAG
+ 000h 4 File ID (usually "VAGp")
+ 004h 4 Version (usually 02h, or 20h) (big-endian)
+ 008h 4 Reserved (0) (except when ID="VAGi") (big-endian)
+ 00Ch 4 Channel Size (data size... per channel?) (big-endian)
+ 010h 4 Sample Rate (in Hertz) (eg. 5622h=22050Hz) (big-endian)
+ 014h 0Ch Reserved (0) (except when version=2)
+ 020h 10h Name (ASCII, zeropadded)
+ ... (..) Optional ID string (eg. "STEREO" in upper/lowercase)
+ ... (..) Optional Padding to Data start
+ ... .. ADPCM Data for channel(s) (usually at offset 030h)
+VAG files are used on PSX, PSP, PS2, PS3, PS4. The overall 1-channel mono
+format is same for consoles. But there are numerous different variants for
+interleaved 2-channel stereo data.
+
+VAG Filename Extensions
+ .vag default (eg. many PSX games)
+ .vig 2-channel with interleave=10h (eg. PS2 MX vs ATV Untamed)
+ .vas 2-channel with interleave=10h (eg. PS2 Kingdom Hearts II)
+ .swag 2-channel with interleave=filesize/2 (eg. PSP Frantix)
+ .l and .r 2-channel in l/r files (eg. PS2 Gradius V, PS2 Crash Nitro Kart)
+ .str whatever (eg. P?? Ben10 Galactic Racing)
+ .abc whatever (eg. PSP F1 2009 (v6), according to wiki.xentax.com)
+
+VAG File IDs (header[000h])
+ "VAGp" default (eg. many PSX games)
+ "VAG1" 1-channel (eg. PS2 Metal Gear Solid 3)
+ "VAG2" 2-channel (eg. PS2 Metal Gear Solid 3)
+ "VAGi" 2-channel interleaved (eg. ?)
+ "pGAV" little endian with extended header (eg. PS2 Jak 3, PS2 Jak X)
+ "AAAp" extra header, followed by "VAGp" header (eg. PS2 The Red Star)
+
+VAG Versions (header[004h])
+ 00000000h v1.8 PC
+ 00000002h v1.3 Mac (eg. PSX Wipeout 2097, in SAMPLES.WAD)
+ 00000003h v1.6+ Mac
+ 00000020h v2.0 PC (most common, eg. PSX Perfect Assassin)
+ 00000004h ? (later games, uh when/which?)
+ 00000006h ? (vagconf, uh when/which?)
+ 00020001h v2.1 (vagconf2) ;\with HEVAG coding instead SPU-ADPCM
+ 00030000h v3.0 (vagconf2) ;/(eg. PS4/Vita)
+ 40000000h ? (eg. PS2 Killzone) (1-channel, little endian header)
+
+Reserved Header entries for ID="VAGi"
+ 008h 4 Interleave (little endian) (the other header entries are big endian)
+
+Reserved Header entries for Version=00000002h (eg. PSX Wipeout 2097)
+This does reportedly contain some default "base" settings for the PSX SPU:
+ 014h 2 Volume left 4Eh,82h ;-Port 1F801C00h
+ 016h 2 Volume right 4Eh,82h ;-Port 1F801C02h
+ 018h 2 Pitch (includes fs modulation) A8h,88h ;-Port 1F801C04h +extra bit?
+ 01Ah 2 ADSR1 00h,00h ;-Port 1F801C08h
+ 01Ch 2 ADSR2 00h,E1h ;-Port 1F801C0Ah
+ 01Eh 2 ? A0h,23h ;-Port 1F801C0xh maybe?
+
+Reserved Header entries for Version=00000003h (according to wiki.xentax.com)
+ 01Eh 1 Number of channels (0 or 1=Mono, 2=Stereo)
+
+Reserved Header entries for Version=00020001h and Version=00030000h
+ 01Ch 2 Zero ;if non-zero: force Mono
+ 01Eh 1 Number of channels (0 or 1=Mono, 2=Stereo ;if 10h..FFh: force Mono
+ 01Fh 1 Zero ;if non-zero: force Mono
+Unknown if the above "force Mono" stuff is really needed (maybe it was intended
+to avoid problems with Version=00000002h, and maybe never happens in
+Version=00000003h and up)?
+
+VAG ADPCM Data
+The ADPCM data uses PSX SPU-ADPCM encoding (even on PS2 and up, except PS4 with
+Version=0002001h or Version=00030000h, which do use HEVAG encoding).
+--> SPU ADPCM Samples
+The data does usually start at offset 0030h (except, some files have extra
+header data or padding at that location).
+The first 10h-byte ADPCM block is usually all zero (used to initialize the
+SPU).
+2-channel (stereo) files are usually interleaved in some way.
+
+VAG Endiannes
+The file header entries are almost always big-endian (even so when used on
+little endian consoles). There are a few exceptions:
+ID="VAG1" has little endian [008h]=Interleave (remaining header is big-endian).
+ID="pVAG" has (some?) header entries in little endian.
+Version=40000000h has most or all header entries in little endian (perhaps
+including the version being meant to be 00000040h).
+
+VAG Channels
+VAGs can be 1-channel (mono) or 2-channel (stereo). There is no standarized way
+to detect the number of channels (it can be implied in the Filename Extension,
+Header ID, in Reserved Header entries, in the Name string at [020h..02Fh], in
+optional stuff at [030h], or in a separate VAG Header in the middle of the
+file).
+
+VAG Interleave
+ None default (for 1-channel mono) (and separate .l .r stereo files)
+ 800h when ID="VAG2"
+ [008h] when ID="VAGi" (little-endian 32bit header[008h])
+ 1000h when ID="pGAV" and [020h]="Ster" and this or that
+ 2000h when ID="pGAV" and [020h]="Ster" and that or this
+ 10h when filename extension=".vig"
+ 10h when Version=0002001h or Version=00030000h (and channels=2)
+ filesize/2 when filename extension=".swag"
+ 6000h when [6000h]="VAGp" (eg. PSX The Simpsons Wrestling)
+ 1000h when [1000h]="VAGp" (eg. PS2 Sikigami no Shiro)
+ ...
+
+AAAp Header
+ 000h 4 ID "AAAp"
+ 004h 2 Interleave
+ 006h 2 Number of Channels (can be 1 or 2?)
+ 008h 30h*N VAGp header(s) for each channel, with Version=00000020h
+ ... .. ADPCM Data (interleaved when multiple channels)
+
+See also
+http://github.com/vgmstream/vgmstream/blob/master/src/meta/vag.c ;very detailed
+http://wiki.xentax.com/index.php/VAG_Audio ;rather incomplete and perhaps wrong
+
+CDROM File Audio Sample Sets VAB and VH/VB (Sony)
+-------------------------------------------------
+
+VAB vs VH/VB
+ .VAB contains VAB header, and ADPCM binaries ;-all in one file
+ .VH contains only the VAB header ;\in two separate files
+ .VB contains only the ADPCM binaries ;/
+PSX Perfect Assassin has some v7 .VH/.VB's (in \DATA.JFS:\SND\*.*)
+PSX Resident Evil 2, COMMON\DATA\*.DIE (contains .TIM+.VAB badged together)
+PSX Spider-Man, CD.HED\l2a1.vab is VAB v5 (other VABs in that game are v7)
+PSX Tenchu 2 (MagDemo35: TENCHU2\VOLUME.DAT\5\* has VAB v20h, maybe a typo)
+
+VAB Header (VH)
+ 0000h 4 File ID ("pBAV")
+ 0004h 4 Version (usually 7) (reportedly 6 exists, too) (5, 20h exists)
+ 0008h 4 VAB ID (usually 0)
+ 000Ch 4 Total .VAB filesize in bytes (or sum of .VH and .VB filesizes)
+ 0010h 2 Reserved (EEEEh)
+ 0012h 2 Number of Programs, minus 1 (0000h..007Fh = 1..128 programs)
+ 0014h 2 Number of Tones, minus? (max 0800h?) (aka max 10h per program)
+ 0016h 2 Number of VAGs, minus? (max 00FEh)
+ 0018h 1 Master Volume (usually 7Fh)
+ 0019h 1 Master Pan (usually 40h)
+ 001Ah 1 Bank Attribute 1 (user defined) (usually 00h)
+ 001Bh 1 Bank Attribute 2 (user defined) (usually 00h)
+ 001Ch 4 Reserved (FFFFFFFFh)
+ 0020h 800h Program Attributes 10h-byte per Program 00h..7Fh (fixed size)
+ 0820h P*200h Tone Attributes 200h-byte per Program 00h..P-1 (variable size)
+ xx20h 200h 16bit VAG Sizes (div8) for VAG 00h..FFh (fixed size)
+ xx20h (...) ADPCM data (only in .VAB files, otherwise in separate .VB file)
+Program Attributes (10h-byte per Program, max 80h programs)
+ 000h 1 tones Number of Tones in the Program (Yaroze: 4) (uh?)
+ 001h 1 mvol Master Volume (Yaroze: 0..127)
+ 002h 1 prior (Yaroze: N/A)
+ 003h 1 mode (Yaroze: N/A)
+ 004h 1 mpan Master Panning (Yaroze: 0..127)
+ 005h 1 reserved0
+ 006h 2 attr (Yaroze: N/A)
+ 008h 4 reserved1
+ 00Ch 4 reserved2
+Tone Attributes (20h-byte per Tone, max 10h tones per Program)
+ 000h 1 prior Tone Priority (Yaroze: 0..127, 127=highest)
+ 001h 1 mode Mode (Yaroze: 0=Normal, 4=Reverberation)
+ 002h 1 vol Tone Volume (Yaroze: 0..127)
+ 003h 1 pan Tone Panning (Yaroze: 0..127)
+ 004h 1 center Centre note (in semitone units) (Yaroze: 0..127)
+ 005h 1 shift Centre note fine tuning (Yaroze: 0..127)
+ 006h 1 min Note limit minimum value (Yaroze: 0..127)
+ 007h 1 max Note limit maximum value (Yaroze: 0..127)
+ 008h 1 vibW (Yaroze: N/A)
+ 009h 1 vibT (Yaroze: N/A)
+ 00Ah 1 porW (Yaroze: N/A)
+ 00Bh 1 porT (Yaroze: N/A)
+ 00Ch 1 pbmin Max? value for downwards pitchbend (Yaroze: 0..127)
+ 00Dh 1 pbmax Max value for upwards pitchbend (Yaroze: 0..127)
+ 00Eh 1 reserved1
+ 00Fh 1 reserved2
+ 010h 2 ADSR1 Attack,Decay (Yaroze: 0..127,0..15)
+ 012h 2 ADSR2 Release,Sustain (Yaroze: 0..127,0..31)
+ 014h 2 prog Program number that tone belongs to (Yaroze: 0..127)
+ 016h 2 vag VAG number (Yaroze: 0..254)
+ 018h 8 reserved
+
+VAB Binary (VB) (ADPCM data) (to be loaded to SPU RAM)
+This can contain max 254 "VAG files" (maybe because having two (?) reserved
+8bit numbers?).
+Sony wants the total size of the ADPCM data to be max 7E000h bytes (which would
+occupy most of the 512Kbyte SPU RAM, leaving little space for the echo buffer
+or additional effects).
+Note: The "VAG files" inside of VAB/VB are actually raw SPU-ADPCM data, without
+any VAG file header. The first 10h-byte ADPCM block is usually zerofilled.
+
+CDROM File Audio Sequences SEQ/SEP (Sony)
+-----------------------------------------
+
+SEQ - Single Sequence
+.SEQ contains MIDI-style sequences, the samples for the instruments can be
+stored in a separate .VAB file (or .VH and .VB files).
+Used by Perfect Assassin, DATA.JFS:\SND\*.SEQ (bundled with *.VH and *.VB)
+Used by Croc (MagDemo02: CROC\CROCFILE.DIR\AMBI*.BIN, MAP*.BIN, JRHYTHM.BIN)
+Used by many other games.
+ 000h 4 File ID "pQES"
+ 004h 4 Version (1) (big endian?)
+ 008h 2 Resolution per quarter note (01h,80h)
+ 00Ah 3 Tempo 24bit (8bit:16bit maybe?) (07h,27h,0Eh)
+ 00Dh 2 Rhythm (NN/NN) (04h,02h)
+ 00Fh ... Score data, uh? (with many MIDI KeyOn's: xx,9x,xx,xx)
+ ... 3 End of SEQ (2Fh=End of Track) (FFh,2Fh,00h)
+The "Score data" seems to be more or less same as in Standard Midi Format (.smf
+files), ie. containing timing values and MIDI commands/parameters.
+
+SEP - Multi-Track Sequences
+This is a simple "archive" with several SEQ-like sequences.
+ 000h 4 File ID "pQES" ;same ID as in .SEQ files (!)
+ 004h 2 Version (0) ;value 0, and only 16bit, unlike .SEQ files
+ 006h .. 1st Sequence
+ ... .. 2nd Sequence
+ ... .. etc.
+Sequences:
+ 000h 2 Sequence ID (0000h and up) (big endian) ;-ID number
+ 002h 2 Resolution per quarter note (01h,80h) ;\
+ 004h 3 Tempo 24bit (07h,27h,0Eh) ; as in SEQ files
+ 007h 2 Rhythm (NN/NN) (04h,02h) ;/
+ 009h 4 Data size (big endian, from 00Dh up to including End of SEQ(
+ 00Dh ... Score data, uh? (...) ;\as in SEQ files
+ ... 3 End of SEQ (2Fh=End of Track) (FFh,2Fh,00h) ;/
+Used by Hear It Now (Playstation Developer's Demo) (RCUBE\RCUBE.SEP)
+Used by Rayman (SND\BIGFIX.ALL\0002)
+Used by Monster Rancher (MagDemo06, MR_DEMO\DATA\MF_DATA.OBJ\025B)
+Used by Rugrats (MagDemo19: RUGRATS\DB02\*.SEP and MENU\SOUND\SEPS\*.SEP)
+Used by Rugrats Studio Tour (MagDemo32: RUGRATS\DATA\SEPS\*.SEP)
+Used by Monkey Hero (MagDemo17: MONKEY\BIGFILE.PSX}*.SEP)
+Used by Pitfall 3D
+Used by Blue's Clues: Blue's Big Musical (SEPD chunks in *.TXD)
+
+CDROM File Audio Streaming XA-ADPCM
+-----------------------------------
+
+Audio Streaming (XA-ADPCM)
+Audio streaming is usually done by interleaving the .STR or .BS file's Data
+sectors with XA-ADPCM audio sectors (the .STR/.BS headers don't contain any
+audio info; because XA-ADPCM sectors are automatically decoded by the CDROM
+controller).
+Raw XA-ADPCM files (without video) are usually have .XA file extension.
+
+CDROM File Audio CD-DA Tracks
+-----------------------------
+
+The eleven .SWP files in Wipeout 2097 seem to be CD-DA audio tracks.
+The one TRACK01.WAV in Alone in the Dark, too?
+Other than that, tracks can be accessed via TOC instead of filenames.
+
+CDROM File Archives with Filename
+---------------------------------
+
+ _______________________________ Entrysize=08h ________________________________
+
+WWF Smackdown (MagDemo33: TAI\*.PAC)
+ 000h 4 ID ("DPAC") ;\
+ 004h 4 Unknown (100h) ;
+ 008h 4 Number of files (N) ;
+ 00Ch 4 Directory Size (N*8) ; Header
+ 010h 4 File Data area size (SIZE = Totalsize-Headersize) ;
+ 014h 4 Unknown (1) ;
+ 018h 7E8h Zerofilled (padding to 800h-byte boundary) ;
+ 800h N*8 File List ;
+ ... .. Zerofilled (padding to 800h-byte boundary) ;/
+ ... SIZE File Data area ;-Data area
+ File List entries:
+ 000h 8 Filename ("NAME")
+ 004h 2 File Offset/800h (increasing)
+ 006h 2 File Size/800h
+The DPAC archives can contain generic files (eg .TIM) and child archives (in a
+separate archive format, with ID "PAC ").
+
+ _______________________________ Entrysize=10h ________________________________
+
+Championship Motocross (MagDemo25: SMX\RESHEAD.BIN and RESBODY.BIN)
+RESHEAD.BIN:
+ 000h N*10h File List (220h bytes)
+ File List entries:
+ 000h 8 Filename ("FILENAME", if shorter: terminated by 00h plus garbage)
+ 008h 4 Filesize in bytes
+ 00Ch 4 Offset/800h in RESBODY.BIN (increasing) (or FFFFFFFFh if Size=0)
+RESBODY.BIN:
+ 000h .. File Data (referenced from RESHEAD.BIN)
+
+One (DIRFILE.BIN\w*\sect*.bin)
+ 000h N*10h File List
+ ... .. File Data area
+ File List entries:
+ 000h 0Ch Filename (eg. "FILENAME 001") ;for last entry: "END 000"
+ 00Ch 4 Offset (increasing, N*10h and up) ;for last entry: zero
+
+True Love Story 1 and 2 (TLS*\MCD.DIR and MCD.IMG)
+MCD.DIR:
+ 000h N*10h File List
+ ... 10h End marker (FFh-filled)
+ File List entries:
+ 000h 8 Filename (zeropadded if less than 8 chars)
+ 008h 2 Zero (0000h)
+ 00Ah 2 Size/800h
+ 00Ch 4 Offset/800h in MCD.IMG
+ Note: Filenames are truncated to 8 chars (eg. "FOREST.T" instead "FOREST.TIM")
+MCD.IMG:
+ 000h .. File Data area (encrypted in True Love Story 2)
+In True Love Story 2, the MCD.IMG data is encrypted as follows:
+ init_key_by_filename(name): ;for MCD.IMG (using filenames from MCD.DIR)
+ i=0, key0=0001h, key1=0001h, key2=0001h
+ while i<8 and name[i]<>00h
+ key0=(key0 XOR name[i])
+ key1=(key1 * name[i]) AND FFFFh
+ key2=(key2 + name[i]) AND FFFFh
+ ret
+ init_key_by_numeric_32bit_seed(seed): ;maybe for LINEAR.IMG and PICT.IMG ?
+ key0=(seed) AND FFFFh
+ key1=(seed - (seed*77975B9h/400000000h)*89h) AND FFFFh
+ key2=(seed - (seed*9A1F7E9h/20000000000h)*3527h) AND FFFFh
+ ret
+ decrypt_data(addr,len):
+ for i=1 to len/2
+ key2=key2/2 + (key0 AND 1)*8000h
+ key0=key0/2 + (key1 AND 1)*8000h
+ key1=key1/2 + ((key1/2 OR key0) AND 1)*8000h
+ key0=((((key1+47h) AND FFFFh)/4) XOR key0)+key2+(((key1+47h)/2) AND 1)
+ halfword[addr]=halfword[addr] XOR key0, addr=addr+2
+ ret
+The MCD.* files don't contain any encryption flag. Below are some values that
+could be used to distinguish between encrypted and unencrypted MCD archives
+(though that may fail in case of any other games/versions with other values):
+ Item Unencrypted Encrypted
+ Parent Folder name "TLS" "TLS2"
+ First name in MCD.DIR "BACKTILE" "TEST.RPS"
+ First word in MCD.IMG 00000010h 074D4C8Ah
+
+Star Wars Rebel Assault 2 (RESOURCE.*, and nested therein)
+BallBlazer Champions (*.DAT, and nested therein)
+The Rebel RESOURCE.* files start with name "bigEx" or "fOFS", BallBlazer *.DAT
+start with "SFXbase" or "tpage", nested files start with whatever other names.
+ 000h N*10h File List
+ ... (4) CRC32 on above header (Top-level only, not in Nested archives)
+ ... .. File Data area
+ ... (..) Huge optional padding to xx000h-byte boundary (in BallBlazer .DAT)
+ File List entries in Top-level archives (with [0Ch].bit31=1):
+ 000h 8 Filename (zeropadded if less than 8 chars)
+ 008h 4 Decompressed Size (or 0=File isn't compressed)
+ 00Ch 4 Offset, self-relative from current List entry (plus bit31=1)
+ File List entries in Nested archives (with [0Ch].bit31=0):
+ 000h 0Ch Filename (zeropadded if less than 12 chars)
+ 00Ch 4 Offset, self-relative from current List entry (plus bit31=0)
+ Last File List entry has [00h..0Bh]=zerofilled, and Offset to end of file.
+Uncompressed Data Format (when List entry [08h]=0 or [0Ch].bit31=0):
+ 000h .. Uncompressed Data
+ ... .. CRC32 on above Data (Top-level only, not in Nested archives)
+Compressed Data Format (when List entry [08h]>0 and [0Ch].bit31=1)::
+ 000h 1 Compression Method (01h=LZ/16bit, 02h=LZ/24bit)
+ 001h 3 Decompressed Size (big-endian)
+ 004h .. Compressed Data
+ ... .. Zeropadding to 4-byte boundary
+ ... .. CRC32 on above bytes (method, size, compressed data, padding)
+--> CDROM File Compression RESOURCE (Star Wars Rebel Assault 2)
+
+ _______________________________ Entrysize=14h ________________________________
+
+Fighting Force (MagDemo01: FGHTFRCE\*.WAD)
+ 000h 4 Number of files (big endian)
+ 004h N*14h File List
+ ... .. File Data
+File List entries:
+ 000h 0Ch Filename ("FILENAME.EXT", zeropadded if shorter than 12 chars)
+ 00Ch 4 Filesize in bytes (can be odd) (big endian)
+ 010h 4 Fileoffset in bytes (increasing, 4-byte aligned) (big endian)
+
+Parappa (MagDemo01: PARAPPA\*.INT)
+Um Jammer Lammy (MagDemo24: UJL\*.INT)
+ 0000h 2000h Folder 1
+ 2000h .. File Data for Folder 1
+ ... 2000h Folder 2
+ ... .. File Data for Folder 2
+ ... 2000h Folder End marker (FFFFFFFFh, plus zeropadding)
+Folder entries:
+ 0000h 4 Folder ID (increasing, 1,2,3, or FFFFFFFFh=End)
+ 0004h 4 Number of files (max 198h) (N)
+ 0008h 4 File Data Area size/800h (S)
+ 000Ch 4 Zero (0)
+ 0010h N*14h File List
+ ... .. Zeropadding to 2000h
+ 2000h S*800h File Data Area for this folder
+File List entries:
+ 000h 4 Filesize in bytes
+ 004h 10h Filename (FILENAME.EXT, zeropadded)
+File Offsets are always 4-byte aligned (required for Um Jammer Lammy, which
+contains Filesizes that aren's multiples of 4).
+Note: There can be more than one folder with same ID (ie. when having more than
+198h TIM files, which won't fit into a single 2000h-byte folder).
+
+Gran Turismo 1 (MagDemo10: GT\BG.DAT\*, GT\COURSE.DAT\*)
+Gran Turismo 1 (MagDemo15: GT\BG.DAT\*, GT\COURSE.DAT\*)
+JumpStart Wildlife Safari Field Trip (MagDemo52: DEMO\DATA.DAT\*.DAT)
+These are child archives found inside of the main GT-ARC and DATA.DAT archives.
+ 000h 4 Number of Files (eg. 26h) (usually at least 02h or higher)
+ 004h N*14h File List
+ ... .. File Data area
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded if shorter)
+ 010h 4 Offset in bytes (increasing, 4-byte-aligned?)
+
+Croc 2 (MagDemo22: CROC2\CROCII.DAT and CROCII.DIR)
+Disney's The Emperor's New Groove (MagDemo39: ENG\KINGDOM.DIR+DAT)
+Disney's Aladdin in Nasira's Revenge (MagDemo46: ALADDIN\ALADDIN.DIR+DAT)
+ DIR:
+ 000h 4 Number of Entries (0Eh)
+ 004h N*14h File List
+ DAT:
+ 000h .. File Data (referenced from CROCII.DIR)
+File List entries:
+ 000h 0Ch Filename ("FILENAME.EXT", zeropadded if shorter)
+ 00Ch 4 File Size in bytes
+ 010h 4 File Offset in .DAT file (800h-byte aligned, increasing)
+
+Alice in Cyberland (ALICE.PAC, and nested .PAC, .FA, .FA2 archives)
+ 000h N*14h File List
+ ... 14h Zerofilled (File List end marker)
+ ... .. File Data area
+ File List entries:
+ 000h 0Ch Filename ("FILENAME.EXT", zeropadded if shorter)
+ 00Ch 4 Offset (increasing, 4-byte aligned)
+ 010h 4 Filesize in bytes (can be odd, eg. for .FA2 files)
+PAC and FA are uncompressed, FA2 is compressed via some LZ5-variant:
+--> CDROM File Compression LZ5 and LZ5-variants
+
+Interplay Sports Baseball 2000 (MagDemo22:BB2000\DATA\HOG.TOC\UNIFORMS\*.UNI)
+ 000h N*14h File List (3Ch*14b bytes, unused entries are zeropadded)
+ 4B0h .. Data area (TIM files for player uniforms)
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 Offset (zerobased, from begin of Data area, increasing)
+
+ _______________________________ Entrysize=18h ________________________________
+
+Invasion from Beyond (MagDemo15: IFB\*.CC)
+ 000h 0Ch Fixed ID (always "KotJCo01Dir ") (always that same string)
+ 00Ch 4 Number of Files
+ 010h N*18h File List
+ ... .. File Data area
+File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 Offset in bytes (increasing, 1-byte or 4-byte aligned)
+ 014h 4 Filesize in bytes (can be odd)
+Note: Alignment is optional: Files in IFB\HANGAR\*.CC and IFB\MAPS\*.CC use
+4-byte aligned offsets (but may have odd filesizes). Files in IFB\INCBINS\*.CC
+don't use any alignment/padding.
+
+Ghost in the Shell (MagDemo03: GITSDEMO\S01\*.FAC)
+ 000h N*18h File List (18h-bytes each)
+ ... 18h File List end marker (zerofilled)
+ ... .. File Data
+File List entries:
+ 000h 1 Filename Checksum (sum of bytes at [001h..00Dh])
+ 001h 1 Filename Length (excluding ending zeroes) (eg. 8, 9, 10, 12)
+ 002h 0Ch Filename ("FILENAME.EXT", zeropadded if less than 12 chars)
+ 00Eh 2 Unknown (2000h) (maybe attr and/or ending zero for filename)
+ 010h 4 Filesize in bytes (can be odd)
+ 014h 4 Offset (increasing, 4-byte aligned)
+
+Oddworld: Abe's Exodus (MagDemo17: ABE2\*.LVL)
+Oddworld: Abe's Exodus (MagDemo21: ABE2\*.LVL and nested .IDX files)
+ 000h 4 Header Size in bytes (2800h) (can be MUCH bigger than needed)
+ 004h 4 Zero
+ 008h 4 ID "Indx"
+ 00Ch 4 Zero
+ 010h 4 Number of Files (N) (CEh) (can be zero=empty in .IDX files)
+ 014h 4 Header Size/800h (05h)
+ 018h 4 Zero
+ 01Ch 4 Zero
+ 020h N*18h File List
+ ... .. Zeropadding to end of Headersize
+ ... .. File Data area
+File List entries (in .LVL files):
+ 000h 0Ch Filename ("FILENAME.EXT", zeropadded if shorter)
+ 00Ch 4 Offset/800h
+ 010h 4 File Size/800h
+ 014h 4 File Size in bytes
+File List entries (in .IDX files):
+ IDX files use the same File List entry format as LVL, but the offsets
+ seem to refer to an external file with corresponding name, for example:
+ cdrom:\ABE2\CR.LVL\CR.IDX ;directory info
+ cdrom:\ABE2\CR.MOV ;external data (the .MOV being a .STR video)
+ XXX: That's not tested/verified, and not implemented in no$psx file viewer.
+
+Monkey Hero (MagDemo17: MONKEY\BIGFILE.PSX and nested .PSX files)
+ 000h 4 Unknown (6)
+ 004h 4 Total Filesize (1403800h)
+ 008h 2 Unknown, Alignment? (800h)
+ 00Ah 2 Number of Files, excluding zerofilled File List entries (ACh)
+ 00Ch 4 Header Size (1800h)
+ 010h 4 Unknown, Entrysize? (18h)
+ 014h 4 Unknown, Entrysize? (18h)
+ 018h N*18h File List (can contain unused zerofilled entries here and there!)
+ ... .. File Data area
+File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 File Offset in bytes (800h-byte aligned, unusorted/not increasing)
+ 014h 4 File Size in bytes
+
+NHL Faceoff '99 (MagDemo17: FO99\*.KGB and nested *.PRM *.TMP *.ZAM)
+NHL Faceoff 2000 (MagDemo28: FO2000\*.KGB, Z.CAT, and nested *.PRM and *.TMP)
+ 000h 4 ID "KGB",00h
+ 004h 4 Number of Files (N)
+ 008h (4) Number of Files negated (-N) ;<-- optional, not in LITESHOW.KGB
+ ... N*18h File List
+ ... (..) CBh-padding to alignment boundary (only if align=800h)
+ ... .. File Data area
+File List entries:
+ 000h 10h Filename ("FILENAME.EXT", terminated by 00h, padded with CDh)
+ 010h 4 File Size in bytes
+ 014h 4 File Offset (800h-byte or 1/4-byte? aligned)
+
+Syphon Filter 1 (MagDemo18: SYPHON\SUBWAY.FOG) (4Mbyte, namelen=10h)
+ 000h 4 Unknown (80000001h)
+ 004h 4 Offset/800h to Final Padding area
+ 008h 8 Zerofilled
+ 010h N*18h File List
+ ... (..) CDh-padding to 800h-byte alignment boundary
+ ... .. File Data area
+ ... 800h Some text string talking about "last-sector bug"
+ ... 40BEh Final Padding area (CDh-filled)
+File List entries:
+ 000h 10h Filename ("FILENAME.EXT", terminated by 00h, padded with CDh)
+ 010h 4 File Offset/800h (increasing)
+ 014h 4 File Size/800h
+This is almost same as the newer v2 format in Syphon Filter 2 (see there for
+details).
+
+Centipede (MagDemo23: ARTFILES\*.ART)
+ 000h 0Fh ID ("Art", zeropadded) ;\
+ 00Fh 1 Type or so ("?") ; sorts of File List entry
+ 010h 4 Number of entries plus 1 (N+1) ; for root folder
+ 014h 4 Total Size in bytes (can be odd) ;/
+ 018h N*18h File List
+ ... ... File Data area
+ File List entries:
+ 000h 0Fh Filename ("FILENAME", zeropadded)
+ 00Fh 1 Type/extension or so ("X" or "D")
+ 010h 4 File Offset (unaligned, increasing)
+ 014h 4 File Size in bytes (can be odd)
+Note: C0L7.ART includes zerofilled 18h-bytes as last File List entry, BONU.ART
+doesn't have any such zerofilled entry.
+Unknown if this can have child folders (maybe in similar form as the root
+folder entry).
+
+Sheep Raider (MagDemo52: SDWDEMO\*.SDW)
+Sheep Raider (MagDemo54: SDWDEMO\*.SDW)
+ 000h 4 Unknown (301h)
+ 004h 4 Zero (0)
+ 008h 4 Number of files (N)
+ 00Ch N*18h File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 4 Offset (800h-byte aligned, increasing)
+ 004h 4 Filesize in bytes
+ 008h 1 Unknown (01h)
+ 009h 0Fh Filename ("FILENAME.EXT",00h, plus garbage padding)
+The SDW archive contains malformed 200h*1A4h pixel TIMs.
+ Texsize is 6900Eh, but should be 6900Ch = 200h*1A4h*2+0Ch
+ Filesize is 6A000h, but should be 69014h = 200h*1A4h*2+14h
+
+Wing Commander III (*.LIB)
+ 000h 2 Number of Files (C9h)
+ 002h N*18h File List
+ ... (..) Padding to 800h-byte boundary (if any, eg. in MOVIES.LIB)
+ ... .. File data area (800h-byte aligned, or unaligned)
+ File List entries:
+ 000h 4 Filesize in bytes
+ 004h 4 Offset (increasing, 800h-byte aligned, or unaligned)
+ 008h 10h Filename ("filename.ext", zeropadded)
+
+Largo Winch - Commando SAR (LEVELS\*.DCF)
+ 000h 4 ID "DCAT"
+ 004h 4 Number of Entries
+ 008h N*18h File List
+ ... .. Zerofilled (padding to 800h-byte boundary)
+ ... .. File Data area
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", terminated by 00h, plus garbage padding)
+ 010h 4 Filesize in bytes
+ 014h 4 Offset (increasing, 800h-byte aligned)
+
+Policenauts (NAUTS\*.DPK)
+ 000h 4 ID "FRID"
+ 004h 4 Always E0000000h
+ 008h 4 Always 800h (...maybe alignment)
+ 00Ch 4 Number of Entries (N)
+ 010h 4 Header Size (N*18h+20h, plus padding to 800h-byte boundary)
+ 014h 4 Always 18h (...maybe entry size)
+ 018h 8 Zerofilled
+ 020h N*18h File List
+ ... .. Zerofilled (padding to 800h-byte boundary)
+ ... .. File Data area
+ File List entries:
+ 000h 0Ch Filename ("FILENAME.EXT", zeropadded if shorter)
+ 00Ch 4 Offset (increasing, 800h-byte aligned)
+ 010h 4 Filesize in bytes
+ 014h 4 Unknown (checksum? random?)
+
+Actua Ice Hockey 2 (Best Sports Games Ever (demo), AH2\GAMEDATA\*.MAD)
+ 000h N*18h File List
+ ... .. File Data area (directly after File List, without end-code)
+ Note: There is no file-list end-marker (instead, the Offset in 1st File
+ entry does imply the end of File List).
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 Offset (increasing, 4-byte aligned, or unaligned for TXT files)
+ 014h 4 Filesize in bytes (or weird nonsense in SFX.MAD)
+There are several oddities in demo version (unknown if that's in retail, too):
+ SFX.MAD has nonsense Filesize entries (eg. 164h for a 15150h-byte file).
+ FACES.MAD contains only one TIM file... but as 3Mbyte junk appended?
+ RINKS.MAD and TEAMS.MAD start with 0Dh,0Ah,1Ah followed by 4Mbyte junk.
+ MISCFILE.MAD contains several nested .mad files.
+ MISCFILE.MAD\panfont.mad\*.txt --> starts with FF,FE --> that's 16bit Unicode?
+
+Muppet Monster Adventure (MagDemo37: MMA\GAMEDATA+WORLDS*\*.INF+WAD)
+ INF:
+ 000h N*18h File List
+ WAD:
+ 000h .. File Data area
+File List entries:
+ 000h 4 File Offset/800h in .WAD file
+ 004h 4 File Size in bytes
+ 008h 10h Filename ("FILENAME.EXT", zeropadded)
+
+Army Men Air Attack 2 (MagDemo40: AMAA2\*.PCK)
+ 000h 4 Number of entries (N)
+ 004h N*18h File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 Fileoffset (800h-byte aligned, increasing)
+ 014h 4 Filesize in bytes
+
+Mort the Chicken (MagDemo41: MORT\*.PPF and .TPF)
+ 000h 2 Type (31h=TPF with TIMs, 32=PPF with PMDs)
+ 002h 2 Number of entries (N) (can be 0=None, eg. STAGE*\MORT.PPF)
+ 004h 4 File List Size (N*18h)
+ 008h 4 Header Size (always 14h)
+ 00Ch 4 Data area Size (Filesize-14h-N*18h)
+ 010h 4 Data area Offset (14h+N*18h)
+ 014h N*18h File List
+ ... .. File Data area
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 Filesize in bytes
+ 014h 4 Fileoffset (from begin of Data area, increasing)
+
+Hot Wheels Extreme Racing (MagDemo52: US_01293\VEHICLES\*.CAB)
+ 000h 4 ID "BACR" (aka RCAB backwards)
+ 004h 4 Number of entries (N)
+ 008h N*18h File List
+ ... .. File Data area
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 020h 4 Offset (from begin of Data area, increasing, 4-byte aligned)
+ 024h 4 Filesize in bytes (can be odd)
+
+ _______________________________ Entrysize=19h ________________________________
+
+WAD Format (Wipeout 2097)
+PSX Wipeout 2097, cdrom:\WIPEOUT2\SOUND\SAMPLES.WAD:\*.vag
+PSX Wipeout 2097, cdrom:\WIPEOUT2\TRACK*\TRACK.WAD:\*.*
+PSX Wipeout 3 (MagDemo25: WIPEOUT3\*)
+ 000h 2 Number of files
+ 002h N*19h Directory Entries for all files
+ ... .. Data for all files (without any alignment, in same order as above)
+Directory Entries
+ 000h 10h Filename (ASCII, can be lowercase), terminated by 00h, plus garbage
+ 010h 4 Filesize in bytes ;\maybe compressed/uncompressed, or rounded,
+ 014h 4 Filesize in bytes ;/always both same
+ 018h 1 Unknown (always 00h)
+The filesize entry implies offset to next file.
+
+ _______________________________ Entrysize=1Ch ________________________________
+
+Command & Conquer, Red Alert (MagDemo05: RA\*) FAT/MIX/XA
+ 000h 4 Number of entries with location 0=MIX (M=65h)
+ 000h 4 Number of entries with location 1=XA (X=1)
+ 008h M*1Ch File List for location 0=MIX
+ ... X*1Ch File List for location 1=XA
+File List entries:
+ 000h 10h Filename (terminated by 00h, padded with garbage)
+ 010h 4 Offset/800h in DATA.MIX or Offset/930h DATA.XA file (increasing)
+ 014h 4 Filesize in bytes
+ 018h 4 File Location (0=DATA.MIX, 1=DATA.XA)
+
+Syphon Filter 2 (MagDemo30: SYPHON\TRAIN.FOG) (2.8Mbyte, namelen=14h)
+ 000h 4 Unknown (80000001h)
+ 004h 4 Offset/800h to Final Padding area
+ 008h 8 Zerofilled
+ 010h N*1Ch File List
+ ... (..) CDh-padding to 800h-byte alignment boundary
+ ... .. File Data area
+ ... 3394h Final Padding area (CDh-filled)
+File List entries:
+ 000h 14h Filename ("FILENAME.EXT", terminated by 00h, padded with CDh)
+ 014h 4 File Offset/800h (increasing)
+ 018h 4 File Size/800h
+This is almost same as the older v1 format in Syphon Filter 1:
+ v1 (Syphon Filter 1) has filename_len=10h (and filelist_entrysize=18h)
+ v2 (Syphon Filter 2) has filename_len=14h (and filelist_entrysize=1Ch)
+To detect the version: Count the length of the "ASCII chars + 00h byte + CDh
+padding bytes" at offset 10h.
+Note: The FOG archive in Syphon Filter 2 demo version does contain some empty
+dummy files (with intact filename, but with offset=0 and size=0).
+
+ _______________________________ Entrysize=20h ________________________________
+
+Colony Wars (MagDemo02: CWARS\GAME.RSC)
+Colony Wars Venegance (MagDemo14: CWV\GAME.RSC, 8Mbyte)
+ 000h 4 Number of Files
+ 004h N*20h File List
+ ... 10h File List End: Name (zerofilled)
+ ... 4 File List End: Offset (total filesize, aka end of last file)
+ ... 0Ch File List End: Padding (zerofilled)
+ ... .. File Data area
+File List entries:
+ 000h 10h Filename ("FILENAME.EXT", terminated by 00h, padded with garbage)
+ 010h 4 File Offset in bytes (increasing, 4-byte aligned)
+ 014h 0Ch Padding (garbage) (usually 800F68A0h,800F68A0h,800F68A0h)
+Note: Colony Wars Red Sun does also have a GAME.RSC file (but in different
+format, with folder structure).
+
+WarGames (MagDemo14: WARGAMES\*.DAT)
+ 000h 4 Number of Files (1C3h)
+ 004h N*20h File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded, sorted alphabetically)
+ 010h 4 File Offset/800h (unsorted, not increasing)
+ 014h 4 File Size in bytes
+ 018h 4 File Size/800h
+ 01Ch 4 Zero
+
+Running Wild (MagDemo15: RUNWILD\*.BIN)
+ 000h N*20h File List
+ ... 4 File List End Offset/800h (end of last file)
+ ... 4 File List End Size (zero)
+ ... 18h File List End Name (zerofilled)
+ ... .. Padding to 800h-byte boundary (each 20h-byte: 01h, and 1Fh zeroes)
+ ... .. File Data
+File List entries:
+ 000h 4 Offset/800h (increasing)
+ 004h 4 Filesize in bytes
+ 008h 18h Filename ("FILENAME.EXT" or ":NAME" or ":NAME:NAME", zeropadded)
+Files with extension .z or .Z are compressed:
+--> CDROM File Compression Z (Running Wild)
+
+Test Drive Off-Road 3 (MagDemo27: TDOR3\TDOR3.DAT)
+About same as the other Test Drive games, but with shorter filenames.
+ 000h N*20h File List (1920h bytes used; with padding: 5800h bytes in total)
+ ... .. Zeropadding to Headersize (5800h)
+ ... .. File Data area
+ File List entries:
+ 000h 18h Filename ("FILENAME.EXT" or "PATH\FILENAME.EXT", zeropadded)
+ 018h 4 Filesize in bytes
+ 01Ch 4 File (Offset-Headersize)/800h
+TDOR3.DAT contains DOT1 child archives and many RNC compressed files: --> CDROM
+File Compression RNC (Rob Northen Compression)
+
+Tiny Tank (MagDemo23: TINYTANK\*.DSK)
+ 000h 4 ID ("TDSK") ;\
+ 004h 4 Number of Files (1Bh) ; Directory
+ 008h N*20h File List ;/
+ ... 4 1st File Size (same as Size entry in File List) ;\File Data area
+ ... .. 1st File Data ; (each file os
+ ... 4 2nd File Size (same as Size entry in File List) ; preceeded by
+ ... .. 2nd File Data ; a size entry)
+ ... .. etc. ;/
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 File Size in bytes
+ 014h 4 Unknown (35xxxxxxh..372xxxxxh)
+ 018h 4 Unknown (3724xxxxh) (Timestamp maybe?)
+ 01Ch 4 File Offset in bytes (increasing, 4-byte aligned)
+Note: The File Offset points to a 32bit value containing a copy of the
+Filesize, and the actual file starts at Offset+4.
+
+MAG 3 (MagDemo26: MAG3\MAG3.DAT, 7Mbyte)
+ 000h N*20h File List (B60h bytes)
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area (files are AAh-padded to 800h-byte boundary)
+ File List entries:
+ 000h 4 Filesize in bytes
+ 004h 2 File Offset/800h (16bit) (increasing)
+ 006h 1Ah Filename ("FILENAME.EXT" or "PATH\FILENAME.EXT", zeropadded)
+
+Play with the Teletubbies (MagDemo35: TTUBBIES\*.RES)
+ 000h 2 Zero (0000h)
+ 002h 2 Number of Files (N)
+ 004h 4 Data Base (N*20h+10h)
+ 008h 4 Unknown (20h) ;-maybe File List entry size?
+ 00Ch 2 Unknown (10h) ;\maybe filename length and/or header size?
+ 00Eh 2 Unknown (10h) ;/
+ 010h N*20h File List
+ ... .. File Data area
+File List entries:
+ 000h 4 Zero
+ 004h 4 File Offset (increasing, 4-byte aligned, relative to Data Base)
+ 008h 4 File Size in bytes (can be odd)
+ 00Ch 4 Zero
+ 010h 10h Filename ("FILENAME.EXT", zeropadded)
+
+Mat Hoffman's Pro BMX (old demo) (MagDemo39: BMX\FE.WAD+STR) (uncompressed)
+Mat Hoffman's Pro BMX (new demo) (MagDemo48: MHPB\FE.WAD+STR) (compressed)
+ WAD:
+ 000h N*20h File List
+ STR:
+ 000h .. File Data (MagDemo39: 4.5Mbyte, MagDemo48: compressed/2.8Mbyte)
+ File List entries:
+ 000h 14h Filename ("FILENAME.EXT", zeropadded)
+ 014h 4 Offset in bytes, 4-byte aligned, in STR file
+ 018h 4 Filesize, compressed (always rounded to multiple of 4 bytes)
+ 01Ch 4 Filesize, decompressed (zero when not compressed)
+The decompressor is using an Inflate variant with slightly customized block
+headers:
+ - end flag is processed immediately (instead of after the block)
+ - blocktype is only 1bit wide (instead of 2bit)
+ - stored blocks have plain 16bit len (without additional 16bit inverse len)
+Everything else is same as described here:
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+Instead of "tinf_uncompress", use the function below:
+ bmx_tinf_style_uncompress(dst,src)
+ tinf_init() ;init constants (needed to be done only once)
+ @@lop:
+ if tinf_getbit()=0 then goto @@done ;end flag, 1bit
+ if tinf_getbit()=0 then ;blocktype, 1bit
+ tinf_align_src_to_byte_boundary()
+ len=LittleEndian16bit[src], src=src+2 ;get len (without inverse len)
+ for i=0 to len-1, [dst]=[src], dst=dst+1, src=src+1, next i ;uncompressed
+ else
+ tinf_decode_dynamic_trees(), tinf_inflate_compressed_block() ;compressed
+ gpto @@lop
+ @@done:
+ ret
+Note: Apart from the MHPB\FE.WAD archive, many MHPB\*.BIN files seem to be also
+compressed (unknown if that's the same compression method; and, if so, they
+would lack decompressed size info).
+
+ _______________________________ Entrysize=28h ________________________________
+
+Demo Menu, PlayStation Magazine Demo Disc 03-54, MENU.FF
+Used on most PlayStation Magazine Demo Discs (Disc 03-54, except Disc 01-02)
+Used on PlayStation Underground 3.1 (and maybe other issues)
+Used on Interactive CD Sampler Disc Volume 10 (maybe others, but not Vol 4,5)
+ 000h 4 Number of entries (eg. 20h or 28h)
+ 004h N*28h File List
+ ... .. Garbage padding to 800h-byte boundary
+ ... .. File Data
+ ... .. Huge zeropadding to 200000h or 2EE000h (2048Kbyte or 3000Kbyte)
+File List entries:
+ 000h 20h Filename (terminated by 00h, padded with... looks like garbage)
+ 020h 4 Size/800h
+ 024h 4 Offset/800h (increasing)
+Contains .BS, .TIM, .TXT, .VH, .VB files. The size seems to be always(?)
+2048Kbytes, 2992Kbytes, 2000Kbytes, or 3000Kbytes (often using only the first
+quarter, and having the remaining bytes zeropadded).
+
+Test Drive 4 (MagDemo03: TD4.DAT) (headersize=2000h, used=0...h)
+Test Drive 5 (MagDemo13: TD5.DAT) (headersize=3000h, used=1EF8h)
+Demolition Racer (MagDemo27: DR\DD.DAT) (headersize=5000h, used=2328h)
+This is used by several games, with different Headersizes (2000h or 3000h or
+5000h), with Offsets relative to the Headersize. To detect the Headersize, skip
+used entries, skip following zeropadding, then round-down to 800h-byte boundary
+(in case the 1st file contains some leading zeroes).
+ 000h N*28h File List (less than 0C00h bytes used in TD4 demo)
+ ... .. Zeropadding to Headersize (2000h or 3000h or 5000h)
+ ... .. File Data
+File List entries:
+ 000h 20h Filename ("PATH\FILENAME.EXT", zeropadded)
+ 020h 4 Size in bytes
+ 024h 4 (Offset-Headersize)/800h (increasing)
+TD5.DAT and DD.DAT contain DOT1 child archives and many RNC compressed files:
+--> CDROM File Compression RNC (Rob Northen Compression)
+
+Gekido (MagDemo31: GEKIDO\GLOBAL.CD)
+ 0000h N*28h File List
+ 21C0h ... Unknown random gibberish? (23h,E8h,0Ch,1Dh,79h,C5h,24h,...)
+ 4000h ... File Data area
+File List entries:
+ 000h 1Ch Filename ("\PATH\FILENAME.EXT;0", zeropadded)
+ 01Ch 4 Filesize in bytes
+ 020h 4 Fileoffset in bytes (4000h and up, increasing)
+ 024h 4 Filechecksum (32bit sum of all bytes in the file)
+There is no "number of files" entry, and no "file list end marker" (though the
+"random gibberish" might serve as end marker, as long it doesn't start with "\"
+backslash).
+
+Team Buddies (MagDemo37: BUDDIES\BUDDIES.DAT\* and nested *.BND files)
+ 000h 4 ID "BIND"
+ 004h 4 Number of files (N)
+ 008h N*28h File List
+ ... .. File Data area
+File List entries:
+ 000h 20h Filename ("\FILENAME.EXT", zeropadded)
+ 020h 4 File Offset (increasing, 4-byte aligned) ;\see note
+ 024h 4 File Size in bytes (always a multiple of 4) ;/
+Note: There is a 4-byte gap between most files, that appears to be caused by
+weird/bugged alignment handling done as so:
+ size=((filesize+3) AND not 3) ;size entry for curr file (plus 3)
+ offs=((filesize+4) AND not 3)+offs ;offs entry for next file (plus 4 !!!)
+Namely, odd filesizes (eg. for TXT files in BUDDIES.DAT\00D2h..00D7h) are
+forcefully rounded-up to 4 bytes boundary. If that rounding has occurred then
+there is no additional 4-byte gap (but the 4-byte gap will appear if the
+original filesize was already 4-byte aligned).
+
+JumpStart Wildlife Safari Field Trip (MagDemo52: DEMO\DATA.DAT)
+ 000h 4 Number of entries (N)
+ 004h 4 Number of entries (same as above)
+ 008h 4 Number of entries (same as above)
+ 00Ch 4 Number of entries (same as above)
+ 010h N*28 File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 20h Filename ("\PATH\FILENAME.EXT", zeropadded)
+ 020h 4 Offset/800h, from begin of Data area (increasing)
+ 024h 4 Filesize in bytes
+
+ _______________________________ Entrysize=34h ________________________________
+
+Army Men: Air Attack (MagDemo28: AMAA\PAK\*.PAK)
+ 000h 4 Number of Files
+ 004h N*34h File List
+ ... .. Zeropadding to 4000h
+ 4000h .. File Data area
+ File List entries:
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 Filesize in bytes ;\always both same, always
+ 014h 4 Filesize in bytes ;/both multiple of 800h
+ 018h 4 Zero
+ 01Ch 4 Type (07h..1Ah)
+ 020h 4 Subtype (00h..01h)
+ 024h 10h Zero
+The used Type.Subtype values are:
+ 07h.0 .TIM (*.TIM)
+ 07h.01h .TIM (HUD_*.TIM)
+ 08h.0 .TIM (PSTART.TIM)
+ 09h.0 .TIM (FONT.TIM)
+ 0Ah.0 .SFX
+ 0Eh.0 .MBL
+ 10h.0 .ATR
+ 11h.0 .RLC
+ 13h.0 .AST
+ 15h.0 .SCD
+ 16h.0 .TXT (PAUSED.TXT)
+ 17h.0 .TXT (OBJECT*.TXT)
+ 18h.0 .BIN
+ 1Ah.0 Misc (.3DO=TIM, .V=TXT, and TERRAIN.CLP .HI .LIT .MAP .PAT .POB .TER)
+
+ _______________________________ Entrysize=40h ________________________________
+
+Ninja (MagDemo13: NINJA\CUTSEQ\*.WAD and NINJA\WADS\*.WAD)
+ 000h 4 Number of Files (N)
+ 004h 4 Size of File Data area (SIZ) (total filesize-8-N*40h)
+ 008h N*40h File List
+ ... SIZ File Data area
+ File List entries:
+ 000h 4 Filesize in bytes
+ 004h 4 Fileoffset in bytes (zerobased, from begin of File Data area)
+ 008h 38h Filename, zeropadded
+You Don't Know Jack (MagDemo23: YDKJ\RES\*.GLU)
+You Don't Know Jack 2 (MagDemo41: YDKJV2\*\*.GLU)
+ 000h 4 ID ("GLUE")
+ 004h 4 Unknown (always 400h)
+ 008h 4 Number of Files (N)
+ 00Ch 4 Header Size (40h+N*40h)
+ 010h 30h Zerofilled
+ 040h N*40h File List
+ ... .. Garbage padding to alignment boundary
+ ... .. File Data area
+ File List entries:
+ 000h 20h Filename ("FILENAME.EXT", zeropadded)
+ 020h 4 File Offset in bytes (increasing, 800h-byte aligned)
+ 024h 4 File Size in bytes
+ 028h 2 File ID Number 1 (eg. 1-71 for C01.GLU-C71.GLU)
+ 02Ah 2 Unknown (random, checksum, ?)
+ 02Ch 4 File ID Number 2 (eg. increasing: 1, 2, 3)
+ 030h 10h Zerofilled
+Most .GLU files are 800h-byte aligned (except SHORTY\*.GLU and THREEWAY\*GLU
+which use 4-byte alignment).
+The files do start on alignment boundaries, but there is no alignment padding
+after end of last file.
+
+ _______________________________ Entrysize=60h ________________________________
+
+Army Men Air Attack 2 (MagDemo40: AMAA2\*.PCK\*.PAK)
+ 000h 4 Number of entries (N)
+ 010h N*60h File List
+ ... .. Zeropadding to 2000h
+ 2000h .. File Data area
+ File List entries:
+ 000h 4 Timestamp? (BFxxxxh..C0xxxxh) (or zero, in first file)
+ 004h 4 Unknown (always 421C91h)
+ 008h 4 Unknown (200h or 60200h)
+ 00Ch 4 Filesize (uncompressed)
+ 010h 4 Filesize (compressed, or 0 when not compressed)
+ 014h 4 File Checksum (sum of all bytes in uncompressed file data)
+ 018h 4 Unknown (random 32bit value?)
+ 01Ch 10h Filename ("FILENAME.EXT", zeropadded)
+ 02Ch 4 Zerofilled
+ 030h 4 Unknown (0 or 1 or 8)
+ 034h 4 File Type (see below)
+ 038h 8 Zerofilled
+ 040h 4 Offset MSBs (Fileoffset-2000h)/800h ;\increasing, 4-byte aligned
+ 044h 4 Offset LSBs (Fileoffset AND 7FFh) ;/(or zero when filesize=0)
+ 048h 18h Zerofilled
+File Type values are 07h=TIM, 0Ah=SFX, 0Eh=MBL, 10h=ATR, 13h=AST, 15h=SCD,
+19h=VTB, 1Bh=DCS, 1Dh=DSS, 1Eh=STR, 1Fh=DSM, 20h=FNT, 21h=TER, 25h=PMH,
+26h=Misc.
+Most of the files are SCRATCH compressed:
+--> CDROM File Compression LZ5 and LZ5-variants
+There are also several uncompressed files (eg. VERSION.V, *.SFX, and many of
+the TERRAIN.* files).
+
+ _______________________________ Entrysize=90h ________________________________
+
+Grind Session (MagDemo33: GRIND\SLIP.GRV)
+Grind Session (MagDemo36: GRIND\SLIP.GRV)
+Grind Session (MagDemo42: GRIND\SLIP.GRV)
+Grind Session (MagDemo45: GRIND\SLIP.GRV)
+ 000h 4 ID (A69AA69Ah)
+ 004h 4 Number of files (N)
+ 008h N*90h File List
+ ... .. File Data area
+ File List entries:
+ 000h 80h Filename ("DATA\FILENAME.EXT",00h, plus CDh-padding)
+ 080h 4 File Offset in bytes (increasing, 4-byte aligned)
+ 084h 4 File Size in bytes
+ 088h 8 Unknown (random/checksum?)
+
+ _____________________________ Variable Entrysize _____________________________
+
+HED/WAD
+ Used by Spider-Man (MagDemo31,40: SPIDEY\CD.HED and CD.WAD)
+ Used by Spider-Man 2 (MagDemo52: SPIDEY\CD.HED and CD.WAD)
+ Used by Tony Hawk's Pro Skater (MagDemo22: PROSKATE\CD.HED and CD.WAD)
+ Used by Apocalypse (MagDemo16: APOC\CD.HED and CD.WAD) ;with PADBUG
+ Used by MDK (Jampack Vol. 1: MDK\CD.HED and CD.WAD) ;without ENDCODE
+ Used by Mat Hoffman's Pro BMX (old demo) (MagDemo39: BMX\BMXCD.HED+WAD)
+Format of the CD.HED file:
+ 000h .. File Entries (see below)
+ ... (1) End code (FFh) (if any, not present in MDK)
+File Entry format:
+ 000h .. Filename (ASCII, terminated by 00h, zeropadded to 4-byte boundary)
+ ... 4 Offset in CD.WAD (in bytes, usually 800h-byte aligned)
+ ... 4 Filesize (in bytes)
+PADBUG: Apocalypse does append 1..800h bytes alignment padding (instead of
+1..7FFh or 0 bytes).
+
+Dance UK (DATA.PAK)
+ 000h 4 Number of Files (N) (1ADh)
+ 004h 4 Unknown (7) (maybe HeaderSize/800h, same as first Offset/800h ?)
+ 008h 4 Unknown (1430h = 14h+N*0Ch, same as first Name pointer)
+ 00Ch 4 Unknown (1430h = 14h+N*0Ch, same as first Name pointer)
+ 010h 4 Unknown (1430h = 14h+N*0Ch, same as first Name pointer)
+ 014h N*4 Name List (pointers to name strings, 1430h and up) 6B4h bytes
+ ... N*4 Size List (filesize in bytes) 6B4h bytes
+ ... N*4 Offset List (Offset/800h) 6B4h bytes
+ ... N*var Name Strings (ASCII strings, "folder\filename.ext",00h)
+ ... .. Zerofilled (padding to 800h-byte boundary)
+ ... .. File Data area
+
+Kula Quest / Kula World / Roll Away (*.PAK)
+ 000h 4 Number of Files (N)
+ 004h N*8 File List (2x32bit entries: Offset, Size) (unaligned, can be odd)
+ ... N*4 File Name Offsets
+ ... N*var File Name Strings ("FILE NN",0Ah,00h)
+ ... .. Garbage-padding to 4-byte boundary
+ ... (4) Optional extra garbage? ("MON " in ATLANTFI.PAK, MARSFI.PAK, etc.)
+ ... .. File Data area (ZLIB compressed, starting with big-endian 789Ch)
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+
+Largo Winch - Commando SAR (NTEXTURE\*.GRP and LEVELS\*.DCF\*.CAT and *.GRP)
+ 000h 4 ID (12h,34h,56h,78h) (aka 12345678h in big endian)
+ 004h 4 Header Size (offset to File Data area)
+ 008h 4 Number of Entries (can be 0=None, eg. LEVELS\LARGO07.DCF\Z16.CAT)
+ 00Ch N*var Name List (Filenames in form "FILENAME.EXT",00h)
+ ... .. Zeropadding to 4-byte boundary
+ ... N*4 Size List (Filesizes in bytes)
+ ... .. File Data area
+
+Jackie Chan Stuntmaster (RTARGET\GAME.GCF and LEV*.LCF)
+ 000h 4 Number of files (N) (3..EBh) (big-endian)
+ 004h N*Var File List (list size is implied in first file offset)
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 4 File Type (ascii, .LLN .TXI .TPG .RCI .RCP .WDB .PCI .PCP .BLK)
+ 004h 4 File Size (can be odd) (big-endian)
+ 008h 4 File Offset (increasing, 800h-byte aligned) (big-endian)
+ 00Ch 4 Extra Size (0 or 4 or 8) (big-endian)
+ 010h .. Extra Data (if any) (32bit number, or "TEXTURES")
+
+Syphon Filter 1 (MagDemo18: SYPHON\*.HOG, SYPHON\SUBWAY.FOG\*.HOG,SLF.RFF)
+Syphon Filter 2 (MagDemo30: SYPHON\*.HOG, SYPHON\TRAIN.FOG\*.HOG,SLF.RFF)
+ 000h 4 Timestamp? (36xxxxxxh=v1?, 38xxxxxxh=v2?, other=SLF.RFF)
+ 004h 4 Number of Files (N)
+ 008h 4 Base for Offset List (always 14h)
+ 00Ch 4 Base for String Table (v1=N*4+14h, or v2=N*4+18h)
+ 010h 4 Base for File Data (end of String Table plus align 4/800h/920h)
+ 014h N*4 Offsets to File(s) (increasing, first=0, relative to above [010h])
+ ... (4) v2 only: End Offset for Last File (HOG filesize minus [010h])
+ ... .. String Table (filename list in form of "FILENAME.EXT",00h)
+ ... .. Zeropadding to 4-byte or 800h-byte boundary
+ ... .. File Data area
+There are two versions: Syphon Filter 1 (v1) and Syphon Filter 2 (v2):
+ v1 has [0Ch]=N*4+14h (without end-of-last-file entry; use end=total_size)
+ v2 has [0Ch]=N*4+18h (and does have end-of-last-file entry)
+ v1 has STR files in ISO filesystem (not in HOG archives)
+ v2 has STR files in MOVIES.HOG (with [10h]=920h and [14h and up]=sectors)
+Normally, the following is common for v1/v2:
+ v1/v2 has [10h]=data base, aligned to 4 or 800h
+ v1/v2 has [14h and up] in BYTE-offsets, relative to base=[10h]
+ v1/v2 uses HOG format in .HOG files also in SLF.RFF
+ v1/v2 has further .RFF files (but that aren't in HOG format)
+There are several inconsistent special cases for some v2 files:
+ v2 MOVIE.HOG has [10h]=920h (which is meant to mean base="after 1st sector")
+ v2 MOVIE.HOG has [14h and up] in SECTOR-units, with base="after 1st sector"
+ v2 SLF.RFF does contain two HOG archives badged together (plus final padding)
+ v2 has some empty 0-byte .HOG files (at least so in demo version)
+Danger: The special value 920h means that headersize is one 800h-byte sector
+(whereas 920h is dangerously close to REAL headersize, eg. v1 PCHAN.HOG has
+headersize=908h which means one 800h-byte sector plus 108h bytes) (the 920h
+thing should occur only in v2 though, since v1 has STR files stored in ISO
+filesystem instead of in HOG archives).
+
+Electronic Arts 32bit BIGF archives
+ 000h 4 ID "BIGF" (normal case, all big-endian, 4-byte aligned) ;\
+ ID "BIGH" (with [04h]=little-endian instead big-endian) ;
+ ID "BIG4" (with 40h-byte alignment padding instead 4-byte) ;
+ 004h 4 Sum of Header+Filesizes (excluding Padding's!) (big-endian) ; Header
+ 008h 4 Number of entries (N) ;11h (big-endian) ;
+ 00Ch 4 Size of Header (including File List) ;11Fh (big-endian) ;
+ 010h .. File List ;/
+ ... .. Padding to 1/4/8-byte boundary (optional, before each file) ;\Data
+... .. File Data ;/
+File List entries (with variable length names, entries aren't 4-byte aligned):
+ 000h 4 Offset in bytes (increasing, often 4/8-byte aligned) (big-endian)
+ 004h 4 Size in bytes (can be odd, but often rounded to 4-byte) (big-endian)
+ 008h .. Filename (ASCII, terminated by 00h) ;variable length
+ Note: Filenames can be empty ("",00h) (eg. in WCWDEMO\ZSOUND.BIG)
+Used by PGA Tour 96, 97, 98 (*.VIV)
+Used by FIFA - Road to World Cup 98 (MOP*.BK*, Z4TBLS.BIG\*.t, ZMO*.BIG\*.viv)
+Used by Fifa 2000 (Best Sports demo: FIFADEMO\*.BIG, *.SBK, and nested .viv)
+Used by Need for Speed 3 Hot Pursuit (*.VIV)
+Used by WCW Mayhem (MagDemo28: WCWDEMO\*.BIG) (odd filesizes & nameless files)
+This is reportedly also used for various other Electronic Arts games for PC,
+PSX, and PS2 (often with extension *.BIG, *.VIV).
+Reportedly also "BIGH" and "BIG4" exist:
+ http://wiki.xentax.com/index.php/EA_BIG_BIGF_Archive
+Other Electronic Arts file formats (used inside or alongside big archives):
+ https://wiki.multimedia.cx/index.php/Electronic_Arts_Formats_(2) - BNK etc
+
+Electronic Arts 24bit C0FB archives
+ 000h 2 ID C0FBh (C0h,FBh) (big-endian) ;\
+ 002h 2 Size of Header-4 (00h,15h) (big-endian) ; Header
+ 004h 2 Number of Files (00h,01h) (big-endian) ;
+ 006h .. File List ;/
+ 019h .. Padding to 4-byte boundary? ;-Padding
+ 01Ch .. File Data ;-Data
+ ... 4 "CRCF" ;\
+ ... 4 Unknown (0C,00,00,00) (chunk-size little-endian?) ; Footer
+ ... 4 Unknown (3B,2E,00,00) (checksum maybe?) ;/
+File List entries (with variable length names, and unaligned 24bit values):
+ 000h 3 Offset in bytes (increasing) ;(big-endian, 24bit)
+ 004h 3 Size in bytes ;(big-endian, 24bit)
+ 008h .. Filename (ASCII, terminated by 00h) ;variable length
+Used by FIFA - Road to World Cup 98 (*.BIG)
+Used by Sled Storm (MagDemo24: ART\ZZRIDER.UNI, with 8 files insides)
+
+Destruction Derby Raw (MagDemo35: DDRAW\*.PTH+.DAT, and nested therein)
+ PTH File:
+ 000h N*var File List
+ DAT File:
+ 000h .. File Data area
+File List entries:
+ 000h .. Filename ("FILENAME.EXT",00h) (variable length)
+ ... 4 File Size in bytes (can be odd)
+ ... 4 File Offset in bytes in DAT file (increasing, unaligned)
+Caution: Filenames in PTH archives aren't sorted alphabetically (so DAT isn't
+always guaranteed to be the previous entry from PTH, namely, that issue occurs
+in MagDemo35: DDRAW\INGAME\NCKCARS.PTH\*.PTH+DAT).
+Caution: The whole .DAT file can be compressed: If the sum of the filesizes in
+PTH file does exceed the size of the DAT file then assume compression to be
+used (normally, the top-level DATs are uncompressed, and nested DATs are
+compressed).
+--> CDROM File Compression PCK (Destruction Derby Raw)
+
+SnoCross Championship Racing (MagDemo37: SNOCROSS\SNOW.TOC+.IMG)
+ TOC:
+ 000h N*var File List
+ IMG:
+ 000h .. File Data area
+File List entries:
+ 000h .. Filename ("DATA\FILENAME.EXT",00h) (variable length)
+ ... 4 File Offset (increasing, 800h-byte aligned, in .IMG file)
+ ... 4 File Size in bytes
+Resembles DDRAW\*.PTH+.DAT (but Offset/Size are swapped, and uses 800h-align).
+Note: The archive contains somewhat corrupted TGA's:
+ TGA[10h..11h] = 08h,08h ;bpp=8 (okay) and attr=8 (nonsense)
+ TGA[10h..11h] = 10h,01h ;bpp=16 (okay) and attr=1 (okay) but it's yflipped
+
+CDROM File Archives with Offset and Size
+----------------------------------------
+
+Crash Team Racing (retail: BIGFILE.BIG, and MagDemo30/42: KART\SAMPLER.BIG)
+ 000h 4 Zero
+ 004h 4 Number of Files (260h)
+ 010h N*8 File entries
+ ... .. Zeropadding to 800h byte boundary
+ ... .. File Data
+File Entries:
+ 000h 4 Fileoffset/800h (increasing)
+ 004h 4 Filesize in bytes
+Filetypes in the archive include...
+ MDEC v2 STR's (file 1E1h..1F8h,1FAh)
+ TIM textures (file 01FBh..0200h and others)
+ empty files (file 01F9h and others)
+ small archives with named entries (file B5h,124h,125h,126h and others)
+ stuff with date string and names (file 253h,256h)
+ there seem to be no nested BIG files inside of the main BIG file
+
+Black Matrix (*.DAT)
+ 000h 4 Number of files (N) (eg. 196h)
+ 004h 4 Unknown (always 0Bh) (maybe sector size shift?)
+ 008h N*4 File List
+ ... .. Zeropadding to 800h-byte boudary
+ ... .. File Data
+File List entries:
+ 000h 2 Offset/800h (increasing)
+ 002h 2 Size/800h (can be zero)
+The "files" might actually contain small child folders? Or the whole stuff is
+just some kind of data structure, not an actual file system archive.
+
+Charumera (*.CVF)
+ 000h N*4 File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 1 Size/800h (8bit)
+ 001h 3 Offset/800h (24bit, increasing)
+
+Vs (MagDemo03: THQ\*) has .CDB archives
+ 000h N*8 File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data
+ ... .. Garbage padding (can be several megabytes tall)
+File List entries:
+ 000h 2 Offset/800h (increasing)
+ 002h 2 Size/800h (same as below, rounded up to sector units)
+ 004h 4 Size in bytes
+Note: The files may consist of multiple smaller files badged together (eg.
+DISPLAY.CDB contains several TIMs per file).
+Some CDB archives have garbage padding at end of file: BIN.CDB (2Kbyte),
+CSEL.CDB (80K), DISPLAY.CDB (70K), MOT.CDB (10648Kbyte). Maybe that's related
+to deleted files in the Vs demo version and/or to updating the CDB archives
+with newer/smaller content, but without truncating the CDB filesize
+accordingly.
+
+Monster Rancher (MagDemo06: MR_DEMO\*.OBJ)
+Deception III Dark Delusion (MagDemo33: DECEPT3\K3_DAT.BIN)
+Star Trek Invasion (MagDemo34: STARTREK\STARTREK.RES)
+Similar as .CDB archives (but with 32bit offset, and without duplicated size).
+ 000h N*8 File List
+ ... 4 File List end marker (00000000h)
+ ... .. Garbage padding to 800h-byte boundary
+ ... .. File Data
+File List entries:
+ 000h 4 Offset/800h (increasing)
+ 004h 4 Size in bytes (often zero; for unused file numbers)
+Note: Files are usually padded with 0..7FFh bytes to 800h-byte boundary, but
+STARTREK.RES does append additional 800h-byte padding after each file (ie.
+800h..FFFh padding bytes in total).
+
+Einhander (MagDemo08: BININDEX.BIN/BINPACK0.BIN/BINPACK1.BIN)
+ 000h X*4 File List for BINPACK0.BIN ;\
+ ... .. Zeropadding ; BINPACK0
+ 410h .. Unknown (some/all of it looks like garbage) ;/
+ 800h Y*4 File List for BINPACK1.BIN ;\
+ ... .. Zeropadding ; BINPACK1
+ C10h .. Unknown (some/all of it looks like garbage) ;/
+File List entries:
+ 000h 2 Offset/800h in BINPACK0.BIN or BINPACK1.BIN
+ 002h 2 Size/800h
+
+SO98 Archives (NBA Shootout '98, MagDemo10: SO98\..*.MDL *.TEX *.ANI *.DAT)
+Resembles .BZE (in terms of duplicated size entry).
+ 000h 4 Number of Files
+ 004h 4 Size of File Data area (total filesize-N*0Ch-8)
+ 008h N*0Ch File List
+ ... .. File Data area
+File List entries:
+ 000h 4 Offset (zerobased, from begin of File Data area)
+ 004h 4 Size in bytes
+ 008h 4 Size rounded to mutiple of 4-bytes
+.DAT contains .TIM .SEQ .VB .VH and nested SO98 archives
+.MDL contains whatever (and empty 0-byte files)
+.TEX contains .TIM
+.ANI contains whatever
+
+Gran Turismo 1 (MagDemo10: GT\*.DAT) GT-ARC
+Gran Turismo 1 (MagDemo15: GT\*.DAT) GT-ARC
+Gran Turismo 2 (GT2.VOL\arcade\arc_fontinfo) GT-ARC
+ 000h 0Ch ID "@(#)GT-ARC",00h,00h
+ 00Ch 2 Content Type (8001h=Compressed, 0001h=Uncompressed)
+ 00Eh 2 Number of Files (eg. 0Fh)
+ 010h N*0Ch File List
+ ... .. File Data area
+ File List entries:
+ 000h 4 Offset in bytes (increasing, unaligned)
+ 004h 4 Compressed File Size (can be odd) ;\both same when uncompressed
+ 008h 4 Decompressed File Size ;/(ie. when [00Ch]=0001h)
+MESSAGES.DAT, SOUND.DAT, TITLE.DAT which are completely uncompressed GT-ARC's.
+Most other GT-ARC's contain LZ compressed files. In case of CARINF.DAT it's
+vice-versa, the files are uncompressed, but the GT-ARC itself is LZ compressed
+(the fileheader contains 00h,"@(#)GT-A",00h,"RC",00h,00h; it can be detected
+via those bytes, but lacks info about decompressed size).
+--> CDROM File Compression GT-ZIP (Gran Turismo 1 and 2)
+
+O.D.T. (MagDemo17: ODT\*.LNK and ODT\RSC\NTSC\ALLSOUND.SND and nested LNK's)
+Barbie Explorer (MagDemo50: BARBIEX\*.STR and nested therein)
+ 000h 4 Number of Files (N)
+ 004h N*8 File List
+ ... .. File Data area
+File List entries:
+ 000h 4 Offset in bytes (increasing, 1/4-byte? aligned)
+ 004h 4 File Size in bytes (usually N*4, TXT's in ODT are padded as so)
+Quirk: Instead of rounding only Offsets to N*4 byte boundary, all Sizes are
+rounded to N*4 bytes (eg. TXT files in ODT\RSC\NTSC\GFILES.LNK\01 with odd
+number of characters are are zeropadded to N*4 bytes).
+Note: The PADBUG archives in Final Fantasy VIII (FF8) are very similar (but
+have a different alignment quirk).
+
+Bust A Groove (MagDemo18: BUSTGR_A\*.DFS and BUSTGR_B\*.DFS) (DFS)
+Bust-A-Groove 2 (MagDemo37: BUSTAGR2\BUST2.BIN\*) (main=DF2 and child=DFS)
+Same as in O.D.T. with extra "DFS_" ID at start of file.
+ 000h 4 ID "DFS_" (with align 4) or "DF2_" (with align 800h)
+ 004h 4 Number of Files (N)
+ 008h N*8 File List
+ ... .. File Data area
+ File List entries:
+ 000h 4 Fileoffset in bytes (4-byte or 800h-byte aligned, increasing)
+ 004h 4 Filesize in bytes (can be odd, eg. in BUSTGR_A\SELECT.BPE\*)
+The game does use uncompressed DFS archives (in .DFS files) and compressed DFS
+archives (in .BPE files):
+--> CDROM File Compression BPE (Byte Pair Encoding)
+The game does also use .DBI files (which contain filenames and other strings,
+whatever what for).
+
+Monaco Grand Prix Racing Simulation 2 (MagDemo24: EXE\*\*.SUN)
+Same as DFS, but with Total Filesize instead of "DFS_".
+ 000h 4 Total used filesize (excluding zeropadding to 2EE000h)
+ 004h 4 Number of Files (N)
+ 008h N*8 File List
+ ... .. File Data area
+ ... (..) In some files: Zeropadding to 2EE000h (3072Kbytes)
+File Entries:
+ 000h 4 Offset (increasing, 4-byte aligned, see note)
+ 004h 4 Filesize in bytes (can be odd in Monaco)
+Note: The alignment in Monaco is a bit glitchy:
+ If (Size AND 3)=0 then NextOffset=Offset+Size ;Align4
+ If (Size AND 3)>0 then NextOffset=Offset+Size+Align800h ;Align800h
+ Namely, Monaco has files with Size=3BC5h.
+The first file starts with unknown 32bit value, followed by "pBAV".
+
+Rollcage (MagDemo19: ROLLCAGE\SPEED.IMG) (2Mbyte)
+Rollcage Stage II (MagDemo31: ROLLCAGE\SPEED.IDX+SPEED.IMG) (3Kbyte+9Mbyte)
+Sydney 2000 (MagDemo37: OLY2000\DEMO.IDX+DEMO.IMG) (1Kbyte+2Mbyte)
+ Rollcage 1 uses a single IMG file that contains both directory and data:
+ 000h 4 Header offset (0) ;\
+ 004h 4 Header size (10h+N*10h) ; this seems to be a File List entry
+ 008h 4 Header size (10h+N*10h) ; for the header itself
+ 00Ch 4 Zero ;/
+ 010h N*10h File List ;-File List for actual files
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ Number of files is "IMG[04h]/10h" (minus 1 for excluding the header itself)
+ The other titles have seaparate IDX and IMG files for directory and data:
+ SPEED.IDX = Directory (N*10h bytes File List with offsets into SPEED.IMG)
+ SPEED.IMG = File data
+ Number of files is "Filesize(SPEED.IDX)/10h"
+File List entries:
+ 000h 4 Fileoffset in bytes (800h-byte aligned, increasing)
+ 004h 4 Filesize in bytes
+ 008h 4 When compressed: GT20 Header [004h] (decompressed size)
+ When uncompressed: Same as filesize
+ 00Ch 4 When compressed: GT20 Header [008h] (overlap, usuallly 3, or 7)
+ When uncompressed: Zero
+The compression related entries allow to pre-allocated the decompression buffer
+(without needing to load the actual GT20 file header), and then load the
+comprssed file to the top of the decompression buffer.
+--> CDROM File Compression GT20 and PreGT20
+
+Ultimate 8 Ball (MagDemo23: POOL.DAT) (5.5Mbyte)
+ 000h 4 Number of Entries
+ 004h N*0Ch File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 4 Unknown (random/checksum?)
+ 004h 4 File Offset (800h-byte aligned, increasing)
+ 008h 4 File Size in bytes
+Notes: The LAST file isn't zeropadded to 800h-byte boundary. The File List
+includes some unused entries (all 0Ch-bytes zerofilled).
+
+BIGFOOL - 3D Baseball (BIGFILE.FOO)
+ 000h N*0Ch File List (154h entries)
+ ... N*4 Filename Checksums (?) (154h entries)
+ ... .. Zerofilled (padding to 800h-byte boundary)
+ ... .. File Data area
+The 1st list entry describes the current directory itself, as so:
+ 000h 4 Number of entries (including the 1st entry itself)
+ 004h 4 Offset/800h (always 0, relative from begin of directory)
+ 008h 4 Type (always 3=Directory)
+Further list entries are Files or Subdirectories, as so:
+ 000h 4 For Files: Size in bytes, for Directories: Number of entries
+ 004h 4 Offset/800h (from begin of current directory, increasing)
+ 008h 4 Type (0=File, 3=Directory)
+
+Spec Ops - Airborne Commando (BIGFILE.CAT and nested CAT files therein)
+ 000h 4 File ID (always 01h,02h,04h,08h)
+ 004h 4 Maybe Version? (always 01h,00h,01h,00h)
+ 008h 4 Header Size (18h+N*8+ArchiveNameLength) ;eg. 4ECh
+ 00Ch 4 Sector Alignment (can be 4 or 800h)
+ 010h 4 Number of Files (N) ;eg. 99h
+ 014h 4 Length of Archive Name (including ending 00h)
+ 018h N*8 File entries (see below)
+ ... .. Archive Name, ASCII, terminated by 00h ;eg. "bigfile.dir",00h
+ ... .. Zeropadding to Sector Alignment boundary
+ ... .. File Data
+File Entries:
+ 000h 4 Fileoffset (with above Sector Alignment) (increasing)
+ 004h 4 Filesize in bytes
+Filetypes in the archive include...
+ nested CAT archives (file 07h,0Ch,11h,16h,1Bh,20h,25h,etc)
+ empty files (file 3Eh,5Ah-5Fh,62h-67h,etc)
+ MDEC v2 STR's (file 95h-96h)
+ XA-ADPCM's (inside of nested CAT, in file94h\file*)
+There are "strings" in some files, are those filenames, eg. Icon_xxx etc?
+
+Hot Shots Golf 2 (retail: DATA\F0000.BIN, MagDemo31/42: HSG2\MINGOL2.BIN)
+The DATA directory is 13800h bytes tall. But, the PSX kernel supports max 800h
+bytes per ISO directory (so the kernel can only see the first 33 files in that
+directory). The game isn't actually trying to parse the ISO directory entries,
+instead, it's using the 2800h-byte offset/size list in F0000.BIN to access the
+directory content:
+ 0000h+N*4 1 Sector MM in BCD ;\based at 00:06:00 for file 0
+ 0001h+N*4 1 Sector SS in BCD ; (unused files are set to 00:00:00)
+ 0002h+N*4 1 Sector FF in BCD ;/
+ 0003h+N*4 1 Size MSB in hex (Size/800h/100h)
+ 2000h+N 1 Size LSB in hex (Size/800h AND FFh)
+ 2800h (..) Data area for file 001h..590h (demo version only)
+Retail Version disc layout:
+ Sector 000ADh SCUS_944.76 ;exefile ;\
+ Sector 00130h SYSTEM.CNF ; iso root folder
+ Sector 00131h DATA (sub-folder, 27h sectors) ;/
+ Sector 00158h (padding) ;-padding to 00:06:00
+ Sector 001C2h DATA\F0000.BIN ;file 000h ;\
+ Sector 001C7h DATA\F0001.BIN ;file 001h ;
+ ... ; iso data folder
+ Sector 00B54h DATA\F0032.BIN ;file 020h ;
+ Sector 00B9Bh DATA\F0033.BIN ;file 021h ; ;\files exceeding the 800h
+ ... ... ; ; directory size limit, not
+ Sector 1A0C9h DATA\F1907.BIN ;file 773h ;/ ;/accessible via PSX kernel
+ Sector 1AAF1h DUMMY.BIN ;-iso root folder (padding)
+Demo version in Playstation Magazine is a bit different: It has only two large
+.BIN files (instead of hundreds of smaller .BIN files). The directory is stored
+in first 2800h bytes of MINGOL2.BIN. The MM:SS:FF offsets are numbered as if
+they were located on sector 00:06:00 and up (to get the actual location:
+subtract 00:06:00 and then add the starting sector number of MINGOL2.BIN).
+ Sector 07148h HSG2\MINGOL2.BIN ;file 000h..590h ;demo binary files
+ Sector 0AC1Dh HSG2\MINGOL2X.BIN ;file 76Ch ;demo streaming file(s)
+ Sector 0B032h HSG2\SCUS_944.95 ;exefile ;demo exe file
+Note: File 000h is a dummy entry referring to the 2800h-byte list itself
+(retail file 000h has offset=00:06:00 but size=0, demo file 000h has offset and
+size set to zero). File 001h is the first actual file (at offset=00:06:05, ie.
+after the 2800h-byte list)
+
+Threads of Fate (MagDemo33: TOF\DEWPRISM.HED+.EXE+.IMG)
+The demo version uses "Virtual Sectors" in HED+EXE+IMG files. Apart from that,
+the format is same as for the "Hidden Sectors" in retail version:
+--> CDROM File Archives in Hidden Sectors
+
+WWF Smackdown (MagDemo33: TAI\*.PAC\*, and nested therein)
+These "PAC " files are found in the main archives (which use a separate archive
+format, with ID "DPAC").
+ 000h 4 ID ("PAC ") ;\
+ 004h 4 Number of files (N) ; Header
+ 008h N*8 File List ;/
+ ... .. File Data area ;-Data area
+File List entries:
+ 000h 2 File ID (inreasing, but may skip numbers, ie. non-linear)
+ 002h 3 File Offset (increasing, relative to begin of Data area)
+ 005h 3 File Size
+Bug: TAI\C.PAC\EFFC\0001h has TWO entries with File ID=0002h.
+
+Tyco R/C Racing (MagDemo36: TYCO\MAINRSRC.BFF)
+ 000h 4 Unknown (1)
+ 004h 4 Filelist Offset (800h)
+ 008h 4 Filelist Size (N*8+4) (7ACh)
+ ... .. Padding to 800h-byte boundary (see note)
+ 800h 4 Number of files (N) (F5h)
+ 804h N*8 File List
+ ... .. Padding to 800h-byte boundary (see note)
+ ... .. File Data area
+File List entries:
+ 000h 4 File Offset in bytes (increasing, 800h-byte aligned)
+ 004h 4 File Size in bytes
+Padding Note: Padding after headers & files is weirdly done in two steps:
+ Step 1: Zeropadding to 200h-byte boundary (first 0..1FFh bytes)
+ Step 2: Garbagepadding to 800h-byte boundary (last 0..600h bytes)
+
+Team Buddies (MagDemo37: BUDDIES\BUDDIES.DAT)
+ 000h 2 ID ("BD")
+ 002h 2 Number of files (N)
+ 004h N*8 File List
+ ... .. Zeropadding to 3000h
+ 3000h .. File Data area
+File List entries:
+ 000h 4 File Offset/800h (increasing)
+ 004h 4 File Size in bytes
+
+Gundam Battle Assault 2 (DATA\*.PAC, and nested therein)
+ 000h 4 ID ("add",00h)
+ 004h 4 Fixed (4)
+ 008h 4 Offset to File List (usually/always 20h)
+ 00Ch 4 Number of Files (N)
+ 010h 4 Fixed (10h)
+ 014h 0Ch Zerofilled
+ 020h N*10h File List
+ ... .. File Data area
+File List entries:
+ 000h 4 Offset (increasing, 4-byte aligned) ;\or both zero
+ 004h 4 Size (can be odd) ;/
+ 008h 4 Unknown (0) (or 00h,10h,11h,20h,30h,40h when Offset/Size=0)
+ 00Ch 4 Zero (0)
+
+Incredible Crisis (MagDemo38: IC\*.CDB)
+ 000h 4 Number of files (N)
+ 004h N*4 File List
+ ... .. Zeropadding to 800h-byte boundary
+File List entries:
+ 000h 2 File Offset/800h (increasing)
+ 002h 2 File Size/800h
+
+Ultimate Fighting Championship (MagDemo38: UFC\CU00.RBB)
+ 0000h 4 ID "siff" ;\Header
+ 0004h 4 Total Filesize (DADB1Ch) ;/
+ 0008h 4 ID "RSRC" ;\
+ 000Ch 4 String Size (70h) ; ASCII string
+ 0010h 70h String "RC ver1.0 Copyright",...,00h ;/
+ 0080h 4 ID "RIDX" ;\
+ 0084h 4 File List Size (1F78h) (3EFh*8) ; Directory
+ 0088h N*8 File List (Offset, Size1) ;/
+ 2000h 4 ID "EXIX" ;\
+ 2004h 4 Extended List Size (FBCh) (3EFh*4) ; Extended
+ 2008h N*4 Extended List (Size2) ;/
+ 2FC4h 4 ID "GAP0" ;\Alignment Padding
+ 2FC8h 4 Padding Size (2Ch) ; (so that next chunk
+ 2FCCh 2Ch Padding (1Ah-filled) ;/starts at boundary-8)
+ 2FF8h 4 ID "RBB0" ;\
+ 2FFCh 4 File Data area Size (DAAB1Ch) ; Data area
+ 3000h .. File Data area ;/
+File List entries (RIDX):
+ 000h 4 File Offset (increasing, 4-byte aligned, from ID "RBB0" plus 8)
+ 004h 4 File Size in bytes (can be odd)
+Extended List entries (EXIX):
+ 000h 4 File Size in bytes (always the same size as in RIDX chunk)
+
+Ultimate Fighting Championship (MagDemo38: UFC\CU00.RBB\183h,37Bh..3EBh)
+ 000h 4 ID "OIFF" ;\Header
+ 004h 4 Total Filesize ;/
+ 008h 4 ID "TIMT" or "ANMT" ;\
+ 00Ch 4 Size (N*4) ; Directory Table
+ 010h N*4 File List (offsets from begin of Data ID+8);/
+ ... 4 ID "TIMD" or "ANMD" ;\
+ ... 4 Data Area size (SIZ) (Filesize-18h-N*4) ; Data area
+ ... SIZ Data Area ;/
+
+E.T. Interplanetary Mission (MagDemo54: MEGA\MEGA.CSH+.BIN)
+ MEGA.CSH:
+ 000h N*0Ch File List
+ MEGA.BIN:
+ 000h .. File Data area
+File List entries:
+ 000h 4 Offset (in MEGA.BIN file, 800h-byte aligned, increasing)
+ 004h 4 Unknown (32bit id/random/checksum/whatever)
+ 008h 4 Filesize in bytes
+
+Driver 2 The Wheelman is Back (MagDemo40: DRIVER2\SOUND\*\*)
+ 000h 4 Number of entries (1 or more)
+ 004h N*10h File List
+ ... .. File Data area (.VB aka SPU-ADPCM)
+ File List entries:
+ 000h 4 Offset from begin of Data area, increasing
+ 004h 4 Filesize in bytes
+ 008h 4 Unknown (0 or 1)
+ 00Ch 4 Unknown (AC44h, 0FA0h, 2EE0h, 2710h, 2B11h, 3E80h, 1F40h, etc.)
+ Note: Above AC44h might 44100Hz, or just file number 44100 decimal?
+
+Thrasher: Skate and Destroy (MagDemo27: SKATE\ASSETS\*.ZAL) (Z-Axis)
+Dave Mirra Freestyle BMX (MagDemo36: BMX\ASSETS\*.ZAL) (Z-Axis)
+Dave Mirra Freestyle BMX (MagDemo46: BMX\ASSETS\*.ZAL) (Z-Axis)
+ 000h 4 ID (always 2A81511Ch)
+ 004h 0Ch Zerofilled
+ 010h 1 Unknown (1)
+ 011h 1 Compression Flag for all files (00h=Uncompressed, 80h=Compressed)
+ 012h 2 Number of files (bit0-13?=N, bit14=Unknown, can be set)
+ 014h N*0Ch File List, 12 bytes/entry ;<-- when [11h]=00h=uncompressed
+ 014h N*10h File List, 16 bytes/entry ;<-- when [11h]=80h=compressed
+ ... .. File Data area
+File List entries (0Ch or 10h bytes per entry, depending on compression):
+ 000h 4 File ID (usually 0=first, increasing) (or 0001h,7531h,7532h,...)
+ 004h 4 Offset-10h in bytes (increasing, 4h-byte aligned)
+ 008h 4 Filesize, uncompressed (can be odd)
+ 00Ch (4) Filesize, compressed (can be odd) ;<-- exists only if compressed
+For decompression, see:
+--> CDROM File Compression ZAL (Z-Axis)
+
+Speed Punks (MagDemo32: SPUNKS\*.GDF)
+ 000h 4 ID "0FDG XSP" (aka PSX GDF0 backwards)
+ 008h 4 Header Size (N*10h+10h)
+ 00Ch 4 Number of files (N)
+ 010h N*10h File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 4 ID/Type ("MARV", "MARS", "MARD", "PMET", "COLR", "MROF")
+ 004h 4 ID/Num (usually 1 SHL N, or all zero)
+ 008h 4 Offset (800h-byte aligned, increasing)
+ 00Ch 4 Size in bytes
+
+Legend of Dragoon (MagDemo34: LOD\SECT\*.BIN, and nested therein)
+ 000h 4 ID "MRG",1Ah
+ 004h 4 Number of Files (eg. 0, 1, 2, 193h, 2E7h, or 1DBBh)
+ 008h N*8 File List
+ ... .. Padding to 800h-byte boundary (8Ch-filled) (not in nested MRG's)
+ ... .. File Data area
+ File List entries:
+ 000h 4 Offset/800h, or 4-byte aligned Offset/1 (increasing)
+ 004h 4 Size (can be odd, and can be zero)
+ Size oddities:
+ Empty files in demo version have Size=0 and Offset=0.
+ Empty files in retail version have Size=0 and Offset=OffsetOfNextFile.
+ MRG archives can start or end with Empty files.
+ All files can be empty (eg. retail DRAGN0.BIN\1190h).
+ NumFiles can be zero (eg. retail DRAGN0.BIN\1111h, demo DRAGN0.BIN\10E2h).
+ Offset oddities:
+ SECT\*.BIN have Offset/800h
+ Nested MRGs have 4-byte aligned Offset/1
+ The two variants can be detected as:
+ if FirstOffset=(NumFiles*8+8) then NestedVariant
+ if FirstOffset=(NumFiles*8+8+7FFh) AND NOT 7FFh then RootVariant
+ Whereas, FirstOffset is the first NONZERO offset in file list (important
+ for demo version, which has archives that start with ZERO offsets).
+
+RC Revenge (MagDemo37: RV2\BB\3.BBK and Retail: BB\*\*.BBK)
+This does basically contain four large files (and four info blocks with info on
+the content of those files).
+ 000h 4 Random/Checksum?
+ 004h 4 Faded ID (FADED007h)
+ 008h 4 Part 1 Offset (Sound) (always E5Ch)
+ 00Ch 4 Part 2 Offset (Texture) (when Type=01h: Offset-E5Ch)
+ 010h 4 Part 3 Offset (?) (when Type=01h: Offset-E5Ch)
+ 014h 4 Part 4 Offset (?) (when Type=01h: Offset-E5Ch)
+ 018h 4 Type (10h or 20h=Normal) (or 01h=Special in BB\8\*.BBK)
+ 01Ch B0Ch Part 1 Info (Sound) (when Type=01h: garbage-filled)
+ B28h 314h Part 2 Info (Texture)
+ E3Ch 14h Part 3 Info (?)
+ E50h 0Ch Part 4 Info (?)
+ E5Ch .. Part 1 Data (Sound, SPU-ADPCM data, if any)
+ ... .. Part 2 Data (Texture data) (starts with BDEF1222h or BDEF1111h)
+ ... .. Part 3 Data (?) ;\maybe map, models, and/or whatever
+ ... .. Part 4 Data (?) ;/
+Part 1 Info (Sound info) (if any):
+ 01Ch 4 Random/Checksum?
+ 020h 4 Faded ID (FADED007h)
+ 024h 4 Part 1 Size (eg.7C7F0h)
+ 028h 4 SPU Start Addr (1010h) (for data from file offset E5Ch)
+ 02Ch 4 SPU Middle Addr (eg. 58F70h)
+ 030h 4 SPU End Addr (eg. 7D800h) (start+size)
+ 034h 2 Middle entry number (often 3Ch)
+ 036h 2 Number of used entries-1 (eg. 50h means that 51h entries are used)
+ 038h AF0h Sample List (100 entries, unused ones are zerofilled)
+ 914h 214h Zerofilled (unused 1Ch-byte entries) (total is 1Ch*64h)
+ Sample List entries:
+ 000h 4 SPU Offset (1010h and up) (SpuOffset=1010h is FileOffset=E5Ch)
+ 004h 4 Sample Size in bytes
+ 008h 4 Unknown (0)
+ 00Ch 4 Unknown (0)
+ 010h 4 Pitch (400h=11025Hz, 800h=22050Hz, 2E7h=8000Hz, 8B5h=24000Hz)
+ 014h 4 Unknown (0 or 1)
+ 018h 4 File ID (00001F08h and up)
+Part 2 Info (Texture info):
+ B28h 4 Random/Checksum?
+ B2Ch 4 Faded ID (FADED007h)
+ B30h 4 Part 2 Size (N*16000h) ;Width=2C0h halfwords, Height=N*64
+ B34h 4 Zero (0h)
+ B38h 4 Some RAM Address (8010xxxxh)
+ B3Ch 4 Unknown (eg. 195h or E3h) ;same as at [DA4h]
+ B40h 4+4 VRAM Address X,Y (140h,0) ;maybe load target
+ B48h 4+4 VRAM Address X,Y (140h,0) ;maybe palette base?
+ B50h 4+4 VRAM Address X,Y (xx0h,Height-40h) ;often at/near end of used area
+ B58h 4 Unknown (eg. 1D0h or 1E0h)
+ B5Ch 4 Unknown (eg. 1Ah or 0Dh)
+ B60h 200h Some halfwords? (most are FFFFh, some are 0000h)
+ D60h 40h Zerofilled (0)
+ DA0h 4 Unknown (eg. 185h or E2h)
+ DA4h 4 Unknown (eg. 195h or E3h) ;same as at [B3Ch]
+ DA8h 9x10h Special Texpages (VramX,Y, SizeX,Y, StepX,Y, Flag/Type/Num or so?)
+ E38h 4 Some RAM Address (800Axxxxh)
+Part 3 Info:
+ E3Ch 4 Random/Checksum?
+ E40h 4 Faded ID (FADED007h)
+ E44h 4 Part 3 Size (eg. A9728h or 51264h)
+ E48h 4 RAM End Address (start+size) (eg. 801Fxxxxh) (near memtop)
+ E4Ch 4 RAM Start Address (end-size) (eg. 801xxxxxh)
+Part 4 Info:
+ E50h 4 Random/Checksum?
+ E54h 4 Faded ID (FADED007h)
+ E58h 4 Part 4 Size (usually 10CCCh) (or 105E0h in demo version)
+Note: File CAT\RDS.CAT does also start with ID=FADED007h (but contains whatever
+different stuff).
+
+CDROM File Archives with Offset
+-------------------------------
+
+Below are archives that start with a simple Offset list. The DOT1 and DOTLESS
+types are "standard" archives used by many PSX games (although the "standard"
+was probably independently created by different developers).
+
+DOT1 Archives (named after the ".1" extension in R-Types)
+Used by various titles:
+ R-Types (CG.1, PR\PR.1, and nested inside CG.1)
+ Final Fantasy IX (nested inside FF9.IMG, FF9.IMG\DB, FF9.IMG\DB\DOT1)
+ Legend of Mana (*.EFF,*.SET,*.BTP(?) in folders SND*,SOUND,WM(?))
+ Witch of Salzburg (*.ANM/BIN/BSS/DAT/MDL/SCE)
+ Rayman (RAY\*.XXX, RAY\SND\*.ALL, and nested inside *.XXX)
+ Pandemonium II (JESTERS.PKG\0101\0008 and JESTERS.PKG\0101\000D)
+ Incredible Crisis (MagDemo38: IC\TAN_DAT.CDB\<DOTLESS>\<DOT1>\<SHIFTJIS>)
+ Various games on PlayStation Magazine Demo Discs (Disc 03-54)
+DOT1 (in lack of a better name) is a simple archive format that contains Number
+of Entries and List with Increasing Offsets to File data.
+ 000h 4 Number of Files (N) (eg. 2..18)
+ 004h N*4 File List (offsets to each file, increasing, aligned)
+ ... (4) Optional: Total filesize (aka end-offset for last list entry)
+ ... .. Optional: Zeropadding to alignment boundary (when alignment>4)
+ ... .. File Data
+There are four variants with different alignment (and in some cases, with an
+extra entry with end-offset for last file):
+ Align800h, no extra entry R-Types (CG.1 and PR\PR.1)
+ Align4, no extra entry R-Types (nested in CG.1), FF9 (in IMG, IMG\DB)
+ Align2, no extra entry Incredible Crisis (IC\TAN_DAT.CDB\*\*)
+ Align800h, with extra entry MLB 2000 (DATA.WAD)
+ Align10h, with extra entry Witch of Salzburg (*.ANM/BIN/BSS/DAT/MDL/SCE)
+ Align4, with extra entry Rayman (*.XXX, *.ALL)
+The files can be detected by checking [004h]=4+(N*4), 4+(N*4)+Align800h,
+4+(N*4)+4, or 4+(N*4)+4+Align10h, and checking that the offsets are increasing
+with correct alignment (Rayman has some empty files with same offset), and
+don't exceed the total filesize. And that the alignment space is zeropadded (in
+case of R-Types, only the header is 00h-padded, but files are FFh-padded).
+The detection could go wrong, especially if the archive contains very few
+files, some of the nested DOT1's contain only one file (header "00000001h,
+00000008h", without any further increasing offsets or padding). As workaround,
+accept such files only if they have a ".1" filename extension, or if they were
+found inside of a bigger DOT1, IMG, or DB archive.
+Final Fantasy IX contains some DOT1's with fewer than few entries (the file
+being only 4-bytes tall, containing value NumEntries=00000000h).
+
+NFL Gameday '98 (MagDemo04: GAMEDAY\*.FIL) (32bit) (with nested FIL's)
+NFL Gameday '99 (MagDemo17: GAMEDAY\*.FIL) (32bit)
+NFL Gameday 2000 (MagDemo27: GAMEDAY\*.FIL) (16bit and 32bit)
+NCAA Gamebreaker '98 (MagDemo05: GBREAKER\*.FIL,*.BIN) (16bit and 32bit)
+NCAA Gamebreaker 2000 (MagDemo27: GBREAKER\*.FIL) (16bit and 32bit)
+FIL/32bit (with [02h]=FFFFh):
+ 000h 2 Number of Files (N)
+ 002h 2 ID for 32bit version (FFFFh=32bit entries)
+ 004h N*4 File List (offsets to each file, increasing, 4-byte aligned)
+ ... .. File Data
+FIL/16bit (with [02h]<>FFFFh, eg. FLAG*.FIL and VARS\STARTUP2.FIL\0\*):
+ 000h 2 Number of Files (N)
+ 002h N*2 File List (offsets to each file, increasing, 4-byte aligned)
+ ... .. Zeropadding to 4-byte boundary
+ ... .. File Data
+
+PreSizeDOT1 (Ace Combat 2) (retail and MagDemo01: ACE2.DAT\*)
+Like DOT1, but with Total Filesize being oddly stored at begin of file.
+ 000h 4 Total Filesize (aka end-offset for last list entry)
+ 004h 4 Number of Files (N)
+ 008h N*4 File List (offsets to each file, increasing, 4-byte aligned)
+ ... .. File Data
+Note: Ace Combat 2 contains PreSizeDOT1 (ACE2.DAT\02h..1Dh,36h..B2h) and normal
+DOT1 archives (nested in PreSizeDOT1's and in ACE2.DAT\B3h..E1h).
+
+DOT-T (somewhat same as DOT1, but with 16bit entries)
+Armored Core (MagDemo02, AC10DEMP\*.T)
+ 000h 2 Number of Files
+ 002h N*2 File List (Offset/800h to file data, increasing)
+ ... 2 Total Size/800h (end-offset for last file)
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data
+This can contain many empty 0-byte files (aka unused file numbers; though maybe
+those files exist in the retail version, but not in the demo version).
+
+DOTLESS Archive
+Hot Shots Golf (MagDemo07: HSG\*.DAT)
+Hot Shots Golf 2 (retail: DATA\F0000.BIN\*, MagDemo31/42: HSG2\MINGOL2.BIN\*)
+Starblade Alpha (FLT\*.DAT, TEX\*.DAT)
+Incredible Crisis (MagDemo38: IC\TAN_DAT.CDB\<DOTLESS>)
+ 000h N*4 Offsets to File data (increasing, usually 4-byte aligned)
+ ... (4) Filesize (end-offset for last file) (only in Ape Escape)
+ ... ... File Data
+Like DOT1, but without Number of Files entry (instead, the first offset does
+imply the end of file list). There's no extra entry for end of last file
+(instead, that's implied in the total filesize). Most files have at least 5
+entries, but HSG\TITLE0.DAT seems to contain only one entry (ie. the whole
+header contains only one value, 00000004h, followed by something that looks
+like raw bitmap data).
+Also used by Ape Escape (MINIGAME\* included nested ones), the Ape Escape files
+do have an end-marker with last-offset (that will appear as an empty 0-byte
+file at end of list when not specifically handling it).
+MINIGAME\MINI2\BXTIM.BIN does also have several 0-byte files inside of the file
+list.
+
+Twisted Metal: Small Brawl (MagDemo54: TMSB\SHL\*.TMS)
+ 000h 4 Size of Data Area (total filesize minus 0D0h)
+ 004h 4 Number of files
+ 008h N*4 File List (zerobased offsets from begin of Data Area)
+ ... .. Zeropadding to 0D0h
+ 0D0h .. File Data Area
+This resembles DOT1, with an extra size entry and padding to 0D0h.
+
+Ridge Racer Type 4 (MagDemo19: R4DEMO\R4.BIN, 39Mbyte)
+Ridge Racer Type 4 (MagDemo21: R4DEMO\R4.BIN, 39Mbyte)
+Basically, this is alike DOT1, but SECTOR numbers, and with extra entries...
+ 000h 4 Number of Files (N) (3C9h)
+ 004h N*4 File List (Offset/800h)
+ ... 4 Total Size/800h ;<-- last offset
+ ... 4 Unknown (00,E8,82,2E) ;<-- ??? maybe chksum*800h or so?
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+
+Legend of Legaia (MagDemo20: LEGAIA\PROT.DAT)
+ 000h 4 Zero
+ 004h 4 Number of Entries (4D3h)
+ 008h N*4 File List (Offset/800h)
+ ... 4 Total Size/800h (aka end Offset/800h of last file)
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+The PROT.DAT does not contain filenames, however, it's bundled with CDNAME.TXT,
+which appears to contain symbolic names for (some) indices:
+ #define init_data 0 ;for file 0000h
+ #define gameover_data 1 ;for file 0001h
+ #define town01 3 ;for file 0003h
+ #define town0b 12 ;for file 000Ch
+ ... ;...
+ #define other6 1222 ;for file 04C6h
+ #define other7 1228 ;for file 04CCh
+The DAT file contains many zerofilled "dummy" files with 800h-byte size.
+
+Bloody Roar 1 (MagDemo06: BL\*.DAT)
+Bloody Roar 2 (MagDemo22: ASC,CMN,EFT,LON,SND,ST5,STU\*.DAT)
+ 000h 4 Number of Entries (N)
+ 004h N*4 File List (Offset-(4+N*4), increasing) (or FFFFFFFFh=Unused entry)
+ ... .. File Data area
+Most or all files in DAT archives are PreGT20 compressed.
+--> CDROM File Compression GT20 and PreGT20
+Note: Unused entries can occur anywhere, eg. Bloody Roar 2 CMN\SEL01.DAT does
+have both first and LAST entry marked as unused (FFFFFFFFh). Also, there may be
+a lot of unused entries, eg. Bloady Roar 1 CMN\TITLE00.DAT uses only 5 of 41h
+entries).
+
+Klonoa (MagDemo08: KLONOA\FILE.IDX\*)
+ 000h 4 ID "OA05"
+ 004h N*4 Offset List (usually/always 5 used entries, plus zeropadding)
+ 030h .. File Data area (usually/always starting at offset 30h)
+
+C - The Contra Adventure (DATA\SND\*.SGG)
+ 000h 4 ID "SEGG"
+ 004h 4 Offset to .VH file
+ 008h 4 Offset to .VB file
+ 00Ch 4 Number of .SEQ files (N) (usually 6Eh, or 08h in MENU.SGG)
+ 010h N*4 Offsets to .SEQ files (increasing, unaligned)
+ ... .. SEQ files
+ ... .. Padding to 4-byte boundary
+ ... .. VH file
+ ... .. VB file
+
+Ninja (MagDemo13: NINJA\VRW\*.VRW)
+ 000h 8 ID "VRAM-WAD" (here as archive ID, although same as compress ID)
+ 004h N*4 File List (offsets to Data) ;NumFiles=(FirstOffset-8)/4
+ ... .. Data (compressed .PAK files, which do ALSO have ID="VRAM-WAD")
+The compressed .PAK files are using a LZ5-variant:
+--> CDROM File Compression LZ5 and LZ5-variants
+
+The Next Tetris (MagDemo22: TETRIS\*) has PSX.BSE (and nested therein)
+ 000h 4 Unknown (3)
+ 004h 4 Total Size
+ 008h 4 Number of Files (N) (max 40h, for max 40h*4 bytes in file list)
+ 00Ch N*4 File List (increasing offsets, 800h-byte aligned)
+ ... .. Unknown (looks like garbage padding for unused File List entries)
+ 10Ch 6F4h 42h-filled padding to 800h-byte boundary
+ 800h .. File Data area
+
+Tactics Ogre (UBF*.BIN)
+ 000h 8 Fixed (88h,0,0,0,0,0,0,0)
+ 008h 4 Number of Files (eg. 1Dh or 585h, including last/end file)
+ 00Ch N*4 File List (increasing offsets, 800h-byte aligned)
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+Note: The last file is a TXT file containing "LINK-FILE END....",0Dh,0Ah,1Ah,
+plus zeropadding to 800h-byte boundary.
+
+Spyro the Dragon (MagDemo12: SPYRO\PETE.WAD)
+ 000h 4 Total Filesize (3E800h in Spyro)
+ 004h N*8 File List (1B0h bytes in Spyro)
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data (4-byte aligned, despite of above 800h-byte hdr padding)
+File List entries:
+ 000h 4 Fileoffset (increasing, 4-byte aligned)
+ 004h 4 File ID? (unsorted, not increasing, used range is 000h..1FAh)
+
+CDROM File Archives with Size
+-----------------------------
+
+Disney-Pixar's Monsters, Inc. (MagDemo54: MINC\*.BZE)
+ 000h 4 Zero (0)
+ 004h 4 Type/ID (27100h=160000, 2BF20h=180000, 30D40h=200000 decimal)
+ 008h 4 Number of files
+ 00Ch N*0Ch File List
+ ... .. Zeropadding to 7FCh
+ 7FCh 4 Checksum (32bit sum of SIGN-EXPANDED bytes at [000h..7FBh])
+ ... .. File Data
+File List entries:
+ 000h 4 File Type/ID or so (roughly increasing, eg. 1,3,6,5,7,8,9,A,B)
+ 004h 4 Filesize in bytes
+ 008h 4 Filesize rounded up to multiple of 800h bytes
+
+Bugs Bunny: Lost in Time (MagDemo25: BBLIT\*.BZZ) (without extra entry)
+The Grinch (MagDemo40: GRINCH\*.BZZ) (with extra entry)
+Resembles .BZE, but without the Type entry in Header.
+ 000h 4 Fixed 1 (maybe version, or compression flag)
+ 004h (4) Unknown (000xxxx0h) ;<-- Extra in The Grinch only (not Bunny)
+ ... 4 Number of files
+ ... N*0Ch File List
+ ... .. Zeropadding to 7FCh
+ 7FCh 4 Checksum (32bit sum of SIGN-EXPANDED bytes at [000h..7FBh])
+ ... .. File Data
+File List entries:
+ 000h 4 File Type/ID or so (roughly increasing, eg. 1,2,3,6,5,7,8,9,A)
+ 004h 4 Filesize in bytes (rounded to N*4 even if compressed data is less)
+ 008h 4 Filesize rounded up to multiple of 800h bytes
+Files are compressed, starting with 0Bh, same as in Jersey Devil...
+--> CDROM File Compression BZZ
+Note: The TIM files in Bugs Bunny and The Grinch BZZ archives consists of two
+TIMs badged together: A 4x4 pix dummy TIM, followed by the actual 512x125 pix
+TIM (in some cases followed some extra bytes at end of file?).
+
+Jersey Devil .BZZ (MagDemo10: JD\*.BZZ)
+Resembles .BZE, but without the Type entries in Header and File List, and
+without Header checksum.
+ 000h 4 Fixed 1 (maybe version, or compression flag)
+ 004h 4 Number of files (4)
+ 008h N*8 File List
+ ... .. Zeropadding to 800h-byte boundary (without checksum, unlike .BZE)
+ ... .. File Data
+File List entries:
+ 000h 4 Size in bytes
+ 004h 4 Size rounded to multiple of 800h
+Files are compressed, starting with 0Bh, same as in Bugs Bunny...
+--> CDROM File Compression BZZ
+
+Jackie Chan Stuntmaster (RCHARS\*.RR)
+NBA Basketball 2000 (MagDemo28: FOXBB\*.RR)
+ 000h 2 ID ("PX")
+ 002h 2 Unknown (1 or 3)
+ 004h 4 Header Size (eg. 80h, 7C0h, or 1730h) (N*8+8)
+ 008h N*8 File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 4 Offset (increasing, 800h-byte aligned)
+ 004h 1 Zero
+ 005h 3 Filesize in bytes (24bit) (can be odd)
+Jackie Chan Stuntmaster does always have headersize=1730h (with many unused
+entries with size=0, both in the middle & at the end of File List).
+
+Bomberman World (MagDemo15: BOMBER\*.RC)
+ XXX detect this WITH extension=".RC" check before OBJ
+ (else type=1 could be mistaken as offs=1) (eg RC1\BP0*.RC)
+Resembles .OBJ but contains Filetype? instead of Offset.
+ 000h N*8 File List
+ ... 8 File List end (zerofilled)
+ ... .. Garbage padding to 800h-byte boundary
+File List entries:
+ 000h 4 Filetype (see below)
+ 004h 4 Filesize in bytes
+There can be several files with same type in one .RC archive. Type values are:
+ 00h = End of File List (at least so when Type and Size are both zero)
+ 01h = .TIM
+ 02h = Unknown
+ 03h = Unknown
+ 05h = .VH
+ 06h = .VB
+ 09h = Unknown
+ 0Ah = .TIM (left half of a larger image) (right half has type 01h)
+ 0Bh = Unknown
+ 0Ch = Unknown
+
+Mat Hoffman's Pro BMX (new demo) (MagDemo48: MHPB\BMXCD.HED+WAD)
+This format is used by the NEW demo version on MagDemp48 (the OLD demo version
+on MagDemo39 did use Spider-Man-style HED/WAD format with filenames).
+ HED:
+ 000h 2 Number of entries (N)
+ 002h N*6 File List
+ WAD:
+ 000h ... File data (at 800h-byte aligned locations)
+File List entries:
+ 000h 3 File ID (24bit)
+ 003h 3 File Size in bytes (21bit, max 2Mbyte) (upper 3bit=unused?)
+Note: HED is processed at 80052AC0h in MagDemo48.
+
+Madden NFL 2000 (MagDemo27: MADN00\*.DAT and nested therein)
+Madden NFL 2001 (MagDemo39: MADN01\*.DAT and nested therein)
+ 000h 4 Header Size (N*SectorSize) (xxh, 800h, 1000h, 4800h, or 920h)
+ 004h 4 Sector Size (4=ChildArchive, 800h=MainArchive, 920h=FMV/MADN00)
+ 008h 4 File List entrysize (0=32bit, 1=16bit/MADN00, 4=16bit/MADN01)
+ 00Ch N*2/4 File List (16bit or 32bit filesizes in bytes)
+ ... .. Zeropadding to SectorSize boundary
+ ... .. Files (with above sizes, each zeropadded to SectorSize boundary)
+Dummy files have filesize=1 (but they do nethertheless occupy a whole data
+sector).
+Unknown why the FMV file in MADN00 is using SectorSize=920h (it appears to be
+FORM2 related, although the file seems to be stored in FORM1 sectors, but the
+STR movie appears to work okay despite of the odd size).
+
+Croc 2 (MagDemo22: CROC2\CROCII.DIR\FESOUND.WAD)
+Disney's The Emperor's New Groove (MagDemo39:ENG\KINGDOM.DIR\FESOUND.WAD)
+Disney's Aladdin in Nasira's Rev. (MagDemo46:ALADDIN\ALADDIN.DIR\FESOUND.WAD)
+ 000h 4 Total Filesize-4
+ 004h N*14h File List (2 entries in Croc2, 3 entries in Aladdin/Emperor)
+ ... .. File Data area (SPU-ADPCM( (.VB files with leading zeroes)
+ File List entries: (Aladdin/Emperor) (Croc2)
+ 000h 4 Sample Rate in Hertz (AC44h=44100Hz) (5622h=22050Hz)
+ 004h 2 Sample Rate Pitch (1000h=44100Hz) (0800h=22050Hz)
+ 006h 2 Unknown (7Fh) (32h)
+ 008h 4 Unknown (1) (8)
+ 00Ch 4 Unknown (1FC0001Fh) (40008Fh)
+ 010h 4 Filesize (xxx0h) (xxx0h)
+The number of files is implied in sum of filesizes versus total size.
+
+Dino Crisis 1 and 2 (PSX\DATA\*.DAT and *.DBS and *.TEX) ("dummy header")
+ 000h 800h File List (with 10h or 20h bytes per entry)
+ 800h .. File Data (each file is zeropadded to 800h-byte boundary)
+File List entrysize can be 10h or 20h bytes:
+ Dino Crisis 1 --> always size 10h
+ Dino Crisis 2 --> usually size 20h
+ Dino Crisis 2 --> sometimes size 10h (eg. SC24.DAT, SC48.DAT, WEP_*.DAT)
+File List entries:
+ File List entries, type 0 and 7:
+ 000h 4 Type (0=Data (or .BS pictures), 7=CompressedData)
+ 004h 4 Size
+ 008h 4 RAM Addresss (80000000h..801FFFFFh)
+ 00Ch 4 Zero
+ 010h (10h) Zerofilled
+ File List entries, type 1 and 2 and 8:
+ 000h 4 Type (1=Bitmap, 2=Palette, 8=CompressedBitmap)
+ 004h 4 Size (see below Size Notes)
+ 008h 2 VRAM Address X (0..3FFh)
+ 00Ah 2 VRAM Address Y (0..1FFh) (or 280h in Dino 2 ST703.DAT)
+ 00Ch 2 Width in halfwords (1..400h)
+ 00Eh 2 Height (1..200h)
+ 010h (10h) Zerofilled
+ File List entries, type 3 and 4:
+ 000h 4 Type (3=VoiceHeader("Gian"), 4=VoiceData(SPU-ADPCM))
+ 004h 4 Size
+ 008h 4 SPU Address (0..7FFF0h)
+ 00Ch 2 Unknown (0..7) ;\usually both same (or val1=0, val2>0)
+ 00Eh 2 Unknown (0..7) ;/
+ 010h (10h) Zerofilled
+ File List entries, type 5 (eg. ME*.DAT):
+ 000h 4 Type (5=Unknown... maybe Midi-style or so)
+ 004h 4 Size
+ 008h 4 Load Address (0, or on next 4-byte boundary after previous file)
+ 00Ch 2 Unknown (0..2) ;\always both same
+ 00Eh 2 Unknown (0..2) ;/
+ 010h (10h) Zerofilled
+ File List entries, type 6 and 9:
+ The EXE code does also accept type 6 and 9 (type 6 is handled same as
+ type 0, and type 9 is ignored), but the actual archives don't seem to
+ contain any files with those types.
+ File List entries, padding for unused entries:
+ 000h 10h Type ("dummy header ")
+ 010h (10h) Zerofilled
+Size Notes:
+ Bitmaps and Palettes can have following sizes:
+ Width*Height*2 ;normal case
+ Width*Height*2 + Align(1000h) ;eg. Dino Crisis 1 DOOR*.DAT
+ Width*Height*2 + Align(800h) ;eg. Dino Crisis 2 DOOR27.DAT
+ CompressedBitmaps can have following sizes in compressed form:
+ Less than Width*Height*2 ;normal case
+ Less than Width*Height*2 + 1000h ;eg. Dino Crisis 2 M_RESULT,ST002.DAT
+ CompressedBitmaps can have following sizes after decompression:
+ Width*Height*2 + 8 ;normal case
+ Width*Height*2 + Align(1000h?) + 8 ;eg. Dino Crisis 2 M_RESULT,ST002.DAT
+Note: Dino Crisis DEMO version (MagDemo28: DINO\TRIAL.DAT) does also contain
+"dummy header" DAT archives (but, unlike as in retail version, they are hidden
+somewhere inside of the headerless 14Mbyte TRIAL.DAT archive).
+Type 7 and 8 are using LZSS compression:
+--> CDROM File Compression LZSS (Dino Crisis 1 and 2)
+Apart from LZSS, Type 4 is using SPU-ADPCM compression, and some Type 0 files
+contain .BS compressed pictures (eg. Dino Crisis 2 PSX\DATA\ST*.DBS\*).
+
+CDROM File Archives with Chunks
+-------------------------------
+
+Chunk-based archives have chunk headers for each file, but don't have a central
+directory. That's mainly useful when loading the whole archive to memory.
+
+Interchange File Format (IFF)
+IFF has been invented by Electronic Arts in 1985 on Amiga (hence using 2-byte
+alignment and big-endian size values).
+IFF does mainly define a standarized file structure for use with custom
+group/chunk types (it does also define some Amiga-specific standard audio/video
+types, but those are barely useful on PSX).
+The files are starting with a Group Header, followed by Chunks:
+ Group Header:
+ 000h 4 Group ID ("FORM") (or "LIST" or "CAT " or "PROP")
+ 004h 4 Group Size-08h (SIZ) (filesize-8) (big-endian)
+ 008h 4 Group Type (4-character ASCII) (should be an unique identifier)
+ 00Ch SIZ-4 Chunk(s), and/or nested Group(s)
+ Chunk Format:
+ 000h 4 Chunk Type (4-character ASCII) (meaning depends on Group Type)
+ 004h 4 Chunk Size (SIZ) (big-endian)
+ 00Ch SIZ Data (eg. .TIM, .VB, .VH or custom data)
+ ... .. Zeropadding to 2-byte boundary
+Used by Forsaken (MagDemo09: FORSAKEN\*\*.BND,MP,PCO)
+Used by Star Wars Demolition (MagDemo39,41: STARWARS\*.EXP)
+Used by Turbo Prop Racing (MagDemo11: RRACER\*.IFF, except COURSE.IFF)
+Used by Viewpoint (VIEW.DIR\*.VCF,*.VCS,*.ST*) - some have wrong Size entry?
+Used by Vigilante 8 (MagDemo09: EXAMPLE\*.EXP)
+Used by Wing Commander III (*.LIB\*.IFF)
+Bugs in Viewpoint: fonts\*.vcf have correct Groupsize=Filesize-8, but
+screens\*.vcf have incorrect Groupsize=Filesize-4, and streams\*.vcf have
+weirdest random Groupsize=Filesize+(-04h,+08h,+14h,+5A0h).
+
+Z-Axis little-endian IFF variant
+Unlike real IFF, these are using little-endian, and don't have a Group Type
+entry. There seem to be no nested FORMs. Alignment is kept as 2-byte.
+ Group Header:
+ 000h 4 Group ID ("FORM" or "BODY")
+ 004h 4 Group Size-08h (SIZ) (little-endian)
+ 008h SIZ Chunk(s)
+ Chunk Format:
+ 000h 4 Chunk Type (4-character ASCII)
+ 004h 4 Chunk Size (SIZ) (little-endian)
+ 00Ch SIZ Data
+ ... .. Zeropadding to 2-byte boundary
+ID "FORM" used by Thrasher: Skate and Destroy (MagDemo27: SKATE\ASSETS\*.ZAL\*)
+ID "FORM" used by Dave Mirra Freestyle BMX (MagDemo36,46: BMX\ASSETS\*.ZAL\*)
+ID "BODY" used by Colony Wars (MagDemo02: CWARS\GAME.RSC\*.BND)
+ID "BODY" used by Colony Wars Venegance (MagDemo14: CWV\GAME.RSC\*.BND)
+
+Alice in Cyberland little-endian IFF variant (.TPK)
+Same as Z-Axis IFF variant, except Group IDs are different, and the Header
+sizes are included in the Group/Chunk sizes.
+ Group Header:
+ 000h 4 Group ID ("hTIX","hFNT","hMBD","hHBS")
+ 004h 4 Group Size (total filesize) (little-endian)
+ ... (8) Unknown extra (0,0,0,0,0Ch,0,0,0) ;<-- only in "hHBS" files
+ ... .. Chunk(s)
+ Chunk Format:
+ 000h 4 Chunk Type ("cCLT","cBIT","cSTR","cMAP","cIDX","cVAB","cSEQ")
+ 004h 4 Chunk Size (SIZ) (little-endian)
+ 00Ch SIZ-8 Data
+ ... .. Maybe Zeropadding to boundary? (Chunk Size is always N*4 anyways)
+ID "hTIX" used by Alice in Cyberland (ALICE.PAC\alice.tpk, csel.tpk, etc.)
+ID "hFNT" used by Alice in Cyberland (ALICE.PAC\alice.tpk, juri.tpk, etc.)
+ID "hMBD" used by Alice in Cyberland (ALICE.PAC\*.FA2\*.MBD)
+ID "hHBS" used by Alice in Cyberland (ALICE.PAC\0x_xx.HBS)
+
+Touring Car Championship (MagDemo09: TCAR\GAME\*\*.BFX)
+Jarret & LaBonte Stock Car Racing (MagDemo38: WTC\*\*.BFX)
+Contains several simple chunks:
+ 000h 4 Chunksize in bytes (SIZ) (usually a multiple of 4)
+ 004h SIZ Chunkdata (eg. .TIM file or other stuff)
+There is no end-marker in last chunk (it simply ends at total filesize).
+
+Colony Wars Venegance (MagDemo14: CWV\GAME.RSC\VAG.WAD)
+Colony Wars Red Sun (MagDemo31: CWREDSUN\GAME.RSC\0002\VAG_WAD)
+Contains several simple chunks with filenames:
+ 000h 0Ch Chunk Filename ("filename.ext", zeropadded if shorter)
+ 00Ch 4 Chunk Data Size in bytes (SIZ)
+ 010h SIZ Chunk Data (usually VAGp files, in VAG.WAD)
+There is no end-marker in last chunk (it simply ends at total filesize).
+Red Sun VAG_WAD is a bit odd: The "extension" is _WAD instead .WAD, the chunk
+names include prefix "RedSun\", which leaves only 5 chars for the actual name,
+causig duplicated names like "RedSun\laser" (which were supposedly meant to be
+named laser1, laser2, laser3 or the like), and many of the Red Dun VAG files
+contain damaged 30h-byte VAG header entries, eg. zero instead of ID "VAGp").
+
+Mat Hoffman's Pro BMX (new demo) (MagDemo48: MHPB\STILLS.BIN)
+Contains .BS files in several chunks:
+ 000h .. Chunk(s) (.BS files with extra header info)
+ ... 4 End Marker (00000000h)
+ Chunk format:
+ 000h 4 Chunk size (including whole chunk header)
+ 004h 2 Bitmap Width (eg. F0h)
+ 006h 2 Bitmap Height (eg. 80h)
+ 008h 2 Data Size/4 (same as (Chunksize-0Ch-filenamelen)/4)
+ 00Ah 2 MDEC Size/4 (same as at Data[0])
+ 00Ch .. Filename (eg. "lsFact",00h or "bsRooftop1",00h) ;\filename field
+ ... .. Filename Zeropadding to 4-byte boundary ;/
+ ... .. Data (in BS v2 format) (MDEC Size/4, BS ID 3800h, etc.)
+Note: STILLS.BIN exists in newer BMX demo in MagDemo48 only (not in MagDemo39).
+
+Ridge Racer (TEX*.TMS)
+Ridge Racer Revolution (BIG*.TMS)
+Ridge Racer Type 4 (MagDemo19+21: R4DEMO\R4.BIN\*\*)
+ 000h 4 ID (100h)
+ 004h .. Chunk(s)
+ ... 4 Zero (Chunk Size=0=End)
+ ... .. Optional zeropadding to 800h-byte boundary (in R4.BIN\*)
+Chunk Format:
+ 000h 4 Chunk Size (SIZ)
+ 004h SIZ Chunk Data (TIM file) (note: includes 0x0pix TIMs with palette)
+
+Jet Moto 2 (MagDemo03: JETMOTO2\*.TMS)
+Twisted Metal 2 (MagDemo50: TM2\*.TMS)
+Contains a fileheader and .TIM files in several chunks:
+ 000h 8 ID "TXSPC",0,0,0 (aka CPSXT backwards)
+ 008h 4 Timestamp? (32A5C8xxh)
+ 00Ch 4 Number of Chunks (N) (can be 0=None, eg. TM2\SCREEN\ARROWS.TMS)
+ 010h N*4 Unknown
+ ... N*var Chunks
+ Chunk format:
+ 000h 4 Chunk Size-4 (SIZ)
+ 004h SIZ Chunk Data (TIM file)
+
+Princess Maker - Yumemiru Yousei (BDY\*.BD and PM.*)
+The BDY\*.BD files do simply contain several chunks:
+ 000h .. Chunk(s)
+The PM.* files do contain several "folders" with fixed size:
+ 000h .. Chunk(s) for 1st folder ;\Foldersizes are:
+ ... .. Zeropadding to Foldersize-boundary ; 20000h (PM.DT0 and PM.PCC)
+ ... .. Chunk(s) for 2nd folder ; 28000h (PM.MAP)
+ ... .. Zeropadding to Foldersize-boundary ; 42000h (PM.SD0)
+ ... .. etc. ;/
+Chunk Format:
+ 000h 4 Chunk ID (800000xxh)
+ 004h 4 Chunk Size (size of Data part, excluding ID+Size)
+ 008h .. Data
+The Data for different Chunk IDs does usually have a small header (often with
+w,h,x,y entries, aka width/height, vram.x/y) followed by the actual data body:
+ 80000004h x(2),y(2),width(2),height(2) Bitmap 8bpp ;PM.PCC,MAP
+ 80000005h w(2),h(2),zero(4) Array32bit(w,h) ;PM.MAP
+ 80000006h x(2),width(2) Bitmap Palette ;PM.*
+ 80000007h x(2),y(2),w(1),h(1),zero(2) Array8bit(w,h) ;PM.MAP
+ 80000010h width(2),height(2),x(2),y(2) Bitmap 16bpp ;*.BD
+ 80000012h zero(0) ? ;*.BD
+ 80000014h x(2),y(2),width(2),height(2) Bitmap 4bpp ;PM.DT0
+ 80000016h x(2),y(2),w(1),h(1),n(1),3Fh(1) BitmapArray4bpp(n*2) ;PM.DT0
+ 80000018h ... ? ;PM.PCC
+ 8000001Ah zero(8) ? ;PM.PCC
+ 8000001Ch x(2),y(2),width(2),height(2) Bitmap 1bpp flags? ;*.BD
+ 80000020h zero(8) Sound .SEQ file ;PM.SD0
+ 80000021h zero(8) Sound .VH file ;PM.SD0
+ 80000022h zero(8) Sound .VB file ;PM.SD0
+ 80000024h x(2),zero(6) ? ;PM.DT0\4\0
+ 00000000h Zeropadding to next folder Zeropadding ;PM.*
+
+Project Horned Owl (COMDATA.BIN, DEMODATA.BIN, ROLL.BIN, ST*DATA.BIN)
+ 000h .. Chunks
+Chunk Format:
+ 000h 1 Chunk Type (see below)
+ 001h 3 Unknown (some flags or file ID, or zero in many files)
+ 004h 4 Chunk Size (SIZ)
+ 008h SIZ Chunk Data (eg. SEQ file)
+Chunk Type values:
+ 02h unknown ST*.BIN
+ 05h .TXT ROLL.BIN
+ 05h LZ-compressed TIM DEMODATA.BIN, ST*.BIN (except ST1*.BIN)
+ 06h DOT1 with stuff and TSQ?? ST*.BIN
+ 07h .TMD DEMODATA.BIN, ST*.BIN (except ST1*.BIN)
+ 08h unknown ST*.BIN
+ 09h "PRM:" ST*.BIN
+ 0Ah unknown ST*.BIN
+ 0Bh DOT1 with stuff ST*.BIN (except ST1*.BIN) (odd: ST3*.BIN)
+ 0Ch .SEQ ROLL.BIN, ST*.BIN
+ 0Dh unknown COMDATA.BIN
+ 0Eh unknown ST*.BIN
+ 0Fh DOT1 with LZ-compressed TIMs ST*.BIN
+ 10h DEFLATE-compressed TIM COMDATA.BIN, ROLL.BIN, ST*.BIN
+ 11h DOT1 with stuff ST*.BIN
+ Note: Type=05h can be uncompressed TXT or compressed TIM.
+For detection, the existing .BIN files start with following values:
+ 07 00 00 00 xx xx 00 00 41 00 00 00 .. TMD Model ("A")
+ 0C 00 00 00 xx xx 00 00 70 51 45 53 .. SEQ Midi ("pQES")
+ 0E xx 00 00 08 00 00 00 xx xx xx xx .. Whatever in ST7DATA.BIN (see note)
+ 10 01 00 00 24 28 00 00 EC 9B 7F 70 .. Deflated TIM in COMDATA.BIN
+ 10 08 1A 00 30 0C 00 00 ED 58 4F 88 .. Deflated TIM in ROLL.BIN
+ ST7DATA.BIN has 2 chunks with Type=0Eh, followed by SEQ chunk at offset=20h.
+TIMs are compressed via HornedLZ (Type=05h,0Fh) or Deflate (Type=10h).
+--> CDROM File Compression HornedLZ
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+The game's Inflate function does ignore the 2bit blocktype: All blocks must
+have dynamic trees (fixed trees and uncompressed blocks aren't supported).
+
+See also
+--> CDROM File Archive Darkworks Chunks (Alone in the Dark)
+--> CDROM File Archive Blue Chunks (Blue's Clues)
+--> CDROM File Archive HED/CDF (Parasite Eve 2)
+--> CDROM File Compression LZSS (Serial Experiments Lain)
+--> CDROM File Compression SLZ/01Z (chunk-based compressed archive)
+
+CDROM File Archives with Folders
+--------------------------------
+
+There are several ways to implement folder-like directory trees:
+ - Using multiple archive files nested within each other
+ - Using filenames with path string (eg. "path\filename.ext")
+Other than that, below are special formats with dedicated folder structures.
+
+Archives with Folders
+--> CDROM File Archive HUG/IDX/BIZ (Power Spike)
+--> CDROM File Archive TOC/DAT/LAY
+--> CDROM File Archive WAD (Doom)
+--> CDROM File Archive WAD (Cardinal Syn/Fear Effect)
+--> CDROM File Archive DIR/DAT (One/Viewpoint)
+--> CDROM File Archive HED/CDF (Parasite Eve 2)
+--> CDROM File Archive IND/WAD (MTV Music Generator)
+--> CDROM File Archive GAME.RSC (Colonly Wars Red Sun)
+--> CDROM File Archive BIGFILE.DAT (Soul Reaver)
+--> CDROM File Archive FF8 IMG (Final Fantasy VIII)
+--> CDROM File Archive FF9 IMG (Final Fantasy IX)
+--> CDROM File Archive GTFS (Gran Turismo 2)
+--> CDROM File Archive Nightmare Project: Yakata
+--> CDROM File Archive FAdj0500 (Klonoa)
+See also: PKG (a WAD.WAD variant with folders)
+
+Perfect Assassin (*.JFS)
+ Overall File Structure
+ JFS for root ;\
+ JFS for 1st folder ;\these are dupicated, ; header with complete list
+ JFS for 2nd folder ; also stored in below ; of all file/folder names
+ JFS for 3rd folder ; data area ;
+ etc. ;/ ;/
+ JFS for 1st folder, plus data for files in that folder ;\
+ JFS for 2nd folder, plus data for files in that folder ; data area
+ JFS for 3rd folder, plus data for files in that folder ;
+ etc. ;/
+JFS Headers (0Ch+N*14h bytes)
+ 00h 4 ID "JFS",00h
+ 04h 4 Size in bytes (for root: including nearby child JFS's)
+ 08h 4 Number of file/folder entries in this folder (N)
+ 0Ch N*14h File/Folder entries
+File Entries (with [10h].bit31=0):
+ 00h 12 "FILENAME.EXT" (or zeropadded if shorter)
+ 0Ch 4 Offset from begin of JFS in data area (without any alignment)
+ 10h 4 Size in bytes, plus 00000000h=File
+Folder Entries (with [10h].bit31=1):
+ 00h 12 "DIRNAME.EXT" (or zeropadded if shorter)
+ 0Ch 4 Offset to child JFS in data area
+ 10h 4 Offset to child JFS in header area, plus 80000000h=ChildFolder
+The JFS format is almost certainly unrelated to IBM's "Journaled File System".
+
+Alone in the Dark The New Nightmare (FAT.BIN=Directory, and DATA.BIN=Data)
+ FAT.BIN:
+ 00h 2 Number of folders (X) (43h)
+ 02h 2 Number of files (Y) (8F0h)
+ 04h 4 Unknown (1000h)
+ 08h X*10h Directory Entry 0000h..X-1 (entry 0000h is named "ROOT")
+ .. Y*10h File Entry 0000h..Y-1
+ DATA.BIN:
+ 00h .. File Data area
+Directory Entries (10h bytes):
+ 00h 8 Name (terminated by 00h if less than 8 chars)
+ 08h 2 First Subdirectory number (0001h and up, 0000h would be root)
+ 0Ah 2 Number of Subdirectories (0000h=None, if so above is usually 00FFh)
+ 0Ch 2 First File number (0000h and up)
+ 0Eh 2 Number of files (0000h=None, if so above is usually 00FFh)
+File Entries (10h bytes):
+ 00h 8 Name (terminated by 00h if less than 8 chars)
+ 08h 4 Offset/800h to DATA.BIN
+ 0Ch 4 Size in bytes (when compressed: decompressed size+02000000h)
+Compressed files (in LEVELS\*\* with Size.bit25=1) can be decompressed as so:
+--> CDROM File Compression Darkworks
+The files include some TIM images, WxH images, binary files, and chunks:
+--> CDROM File Archive Darkworks Chunks (Alone in the Dark)
+
+Interplay Sports Baseball 2000 (MagDemo22: BB2000\* HOG.DAT and HOG.TOC)
+ HOG.TOC:
+ 000h N*14h Folder/File List (starting with root folder)
+ HOG.DAT:
+ 000h .. File Data (referenced from HOG.TOC)
+Folder entries:
+ 000h 1 Type ("D"=Directory)
+ 001h 8 Name ("FILENAME", zeropadded if shorter) (or "\" for root)
+ 009h 3 Extension (usually zero for directories)
+ 00Ch 4 Folder Offset/14h in .TOC file (aka 1st child file/folder index)
+ 010h 4 Folder Size/14h (aka number of child files/folders)
+File entries:
+ 000h 1 Type ("F"=File)
+ 001h 8 Name ("FILENAME", zeropadded if shorter)
+ 009h 3 Extension ("EXT", zeropadded if shorter)
+ 00Ch 4 File Offset/800h in .DAT file (increasing)
+ 010h 4 File Size in bytes
+
+Tenchu 2 (MagDemo35: TENCHU2\VOLUME.DAT)
+ 000h 4 Unknown (demo=A0409901h, us/retail=A0617023h)
+ 004h 4 Unknown (0h)
+ 008h 4 Number of files (F) (demo=B7h, us/retail=1294h)
+ 00Ch 4 Number of folders (D) (demo=0Fh, us/retail=3Eh)
+ 010h D*8 Folder List
+ ... .. Zerofilled (padding to 800h-byte boundary)
+ 800h F*10h File List
+ ... .. Zerofilled (padding to 800h-byte boundary)
+ ... .. File Data area
+Folder List entries:
+ 000h 4 Folder ID (Random, maybe folder name checksum?)
+ 004h 4 First file number in this folder (0=first, increasing)
+File List entries:
+ 000h 4 File Offset/800h
+ 004h 4 File Size in bytes
+ 008h 4 Folder ID (same as Parent Folder ID in Folder List)
+ 00Ch 4 File ID (Random, maybe file name checksum?)
+
+Blasto (MagDemo10: BLASTO\BLASTO.DAT and BLASTO\BLASTO.LFS)
+ LFS:
+ 000h N*18h File/Folder List
+ DAT:
+ 000h .. File data
+File entries (with [10h]=Positive):
+ 000h 10h Filename ("FILENAME.EXT", zeropadded)
+ 010h 4 Offset in bytes, in BLASTO.DAT
+ 014h 4 Size in bytes
+Folder entries (with [10h]=Negative):
+ 000h 10h Foldername ("DIRNAME", zeropadded)
+ 010h 4 Index to first child (at Offset=(-Index)*18h in BLASTO.LFS)
+ 014h 4 Zero
+Folder end marker (with [00h]=00h or 80h):
+ 000h 1 End marker, at end of root & child directories (00h or 80h)
+ 001h 17h Unknown
+
+Twisted Metal 4 (MagDemo30: TM4DATA\*.MR and *.IMG)
+These are relative small archives with hundreds of tiny chunks (with registry
+style Symbol=Value assignments), and a few bigger chunks (with .mod .vab .bit
+.clt files).
+ 000h 4 Fixed ID (CCCC0067h)
+ 004h .. Root Folder (with Name="Root",00h,FDh,FDh,FDh)
+ Folder Chunk format:
+ 000h 1 Length of Name (including 4-byte padding)
+ 001h 1 Number of Child Folders
+ 002h 2 Number of Child Files
+ 004h .. Name ("name",00h, CDh-padded to 4-byte boundary; Root=FDh-padded)
+ ... .. Child File(s)
+ ... .. Child Folder(s)
+ File Chunk format:
+ 000h 1 Length of filename (including 4-byte padding)
+ 001h 1 Filetype (see below)
+ 002h 2 Array Size (or FFFFh for non-array filetypes)
+ 004h 4 Filesize (SIZ) (including 4-byte padding)
+ 008h 4 Decompressed Size (or 0=Uncompressed)
+ 00Ch .. Filename/Symbol ("name.ext",00h, CDh-padded to 4-byte boundary)
+ ... SIZ Data/Value (CDh-padded to 4-byte boundary)
+Some filenames have trailing non-ascii characters, for example:
+ "AXEL.MR\display\resolution\r3\Groups\Combined_Polyset",1Ah,01h,04h,00h
+ "CALYPSO.MR\display\resolution\r3\Groups\Combined_Polyset",A8h,00h, CDh,CDh
+Filetypes:
+ Typ Size Expl.
+ 02h var Text String (terminated by 00h, garbage-or-00h-padded to 4-byte)
+ 03h 8 Misc (*.IMG\textures\*) ;\
+ 03h 20h Misc (*.MR\display\resolution\r*\Groups\*) ; these are all
+ 03h var Misc (*.MR\display\resolution\*List) ; filetype=03h
+ 03h file Misc (*.MR\display\*.bit) (same as type=0Ch) ;/
+ 04h 4 Numeric 32bit
+ 05h 8 Numeric 4x16bit point (X,Y,Z,CDCDh)
+ 06h file Model (*.mod) (DOTLESS archive with model data)
+ 0Bh 4 Numeric 32bit repeat,light
+ 0Ch file XYWH Bitmap/Palette (*.bit, *.clt) (in GAME.IMG, MENU\menu)
+ 0Dh 4 Numeric 32bit delay
+ 0Eh 4 Numeric 32bit color (maybe 24bit RGB plus 00h-padding?)
+ 0Fh 10h Whatever 10h-byte "pos"
+ 10h file Sony .VAB file (*.vab)
+ 12h N*1 Array? (with Arraysize=0014h)
+ 16h N*?? Array Text Strings (with Arraysize=0001h) (in MAIN.MR\worlds)
+ 1Ah N*10h Array Guns,startpoints (RCCAR.MR\*, NEON.MR\world)
+ 1Bh 4 Numeric 2x16bit (X,Y) (in MENU.MR)
+ 1Ch N*4 Array lloc (in MENU.MR\menu\screens) (with Arraysize=04h or 1Fh)
+ 25h 8 Whatever 8-byte (in GAME.MR\dualShock)
+ 26h N*8 Array CollideArray (in GAME.MR\dualShock) (with Arraysize=4 or 6)
+Compressed Data (when [008h]<>0):
+ 000h .. ZLIB compressed data (usually starting with big-endian 789Ch)
+ (compression is used for almost all files, except VERY small ones)
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+
+CDROM File Archive HUG/IDX/BIZ (Power Spike)
+--------------------------------------------
+
+Power Spike (MagDemo43: POWER\GAME.IDX and .HUG)
+POWER\GAME.HUG
+ 000h .. File Data
+POWER\GAME.IDX
+ 000h 4 ID "HUGE"
+ 004h 4 Checksum (sum of all bytes at [010h and up])
+ 008h 4 Number of Folders (D) (87h)
+ 00Ch 4 Number of Files (F) (F9h)
+ 010h D*1Ch Folder List (Folder 0..D-1)
+ ... F*18h File List (File 0..F-1)
+Folder List entries:
+ 000h 0Ch Folder Name ("DIRNAME", zeropadded)
+ 00Ch 4 First Child File (or FFFFFFFFh=None)
+ 010h 4 Number of Child Files (or 00000000h=None)
+ 014h 4 First Child Folder (or FFFFFFFFh=None)
+ 018h 4 Next Sibling Folder (or FFFFFFFFh=None)
+File List entries:
+ 000h 0Ch File Name ("FILENAME.EXT", zeropadded if shorter than 12)
+ 00Ch 4 File Checksum (sum of all bytes in file added together)
+ 010h 4 File Offset/800h in GAME.HUG
+ 014h 4 File Size in bytes
+The root entries are Folder 0 (and its siblings). That is, the root can contain
+only folders (not files).
+The IDX/HUG archive contains many BIZ archives (and some TXT files).
+
+Power Spike (MagDemo43: POWER\GAME.IDX\*.BIZ) (BIZ nested in IDX/HUG)
+ 000h 4 ID "BIG!"
+ 004h 4 Number of entries (N)
+ 008h N*1Ch File List
+ ... .. BIZ compressed File Data
+File List entries
+ 000h 10h Filename (zeropadded)
+ 010h 4 File Offset (increasing, unaligned, can be odd)
+ 014h 4 File Size decompressed
+ 018h 4 File Size compressed
+All files in the BIZ archive are BIZ compressed (unknown if it does also
+support uncompressed files).
+--> CDROM File Compression LZ5 and LZ5-variants
+The BIZ archive seems to be solely containing PSI bitmaps (even files in
+GAME.IDX\SOUND\MUSIC\*.BIZ do merely contain PSI bitmaps, not audio files).
+
+CDROM File Archive TOC/DAT/LAY
+------------------------------
+
+Used in PSX Lightspan Online Connection CD (CD.TOC, CD.DAT, CD.LAY).
+ CD.TOC contains File/Folder entries
+ CD.DAT contains the actual File bodies
+ CD.LAY devkit leftover (list of filenames to be imported from PC to TOC/DAT)
+The .TOC file doesn't have any file header, it does just start with the first
+File/Folder folder entry in root directory. The directory chains with
+file/folder entries are sorted alphabetically, each chain is terminated by a
+final entry which does point to parent directory.
+
+File Entries
+ 00h 4 Offset to next Sibling File/Folder/Final entry
+ 04h 4 Filesize in bytes
+ 08h 4 Filedata Offset/800h in CD.DAT
+ 0Ch .. Filename (ASCII, terminated by 00h)
+ ... .. Padding to 4-byte boundary (garbage)
+
+Folder Entries (with Filesize=FFFFFFFFh)
+ 00h 4 Offset to next Sibling File/Folder/Final entry
+ 04h 4 Filesize (always FFFFFFFFh in Folder entries)
+ 08h 4 Offset to first File/Folder in Child directory
+ 0Ch .. Name of Child directory (ASCII, terminated by 00h)
+ ... .. Padding to 4-byte boundary (garbage)
+
+Final Entries (with Name="",00h and Filesize=FFFFFFFxh)
+ 00h 4 Offset to next Sibling entry (00000000h=None)
+ 04h 4 Filesize (FFFFFFFFh in child folders, FFFFFFFEh in root folder)
+ 08h 4 Offset to first File/Folder in Parent directory (or to self for root)
+ 0Ch 1 Empty Name ("",00h)
+ 0Dh 3 Padding to 4-byte boundary (garbage)
+
+CDROM File Archive WAD (Doom)
+-----------------------------
+
+Doom, PSXDOOM\ABIN\*.WAD and PSXDOOM\MAPDIR*\*.WAD)
+The .WAD format is used by Doom (for DOS, Jaguar, PSX, etc), various homebrew
+Doom hacks, and some other developers have adopted the format and used .WAD in
+other game engines.
+ 000h 4 ID "IWAD" (or "PWAD" for homebrew patches, or "PACK" in A.D. Cop)
+ 004h 4 Number of File List entries (N) (including final ENDOFWAD entry)
+ 008h 4 Offset to Directory Area (filesize-N*10h)
+ 00Ch .. File Data area
+ ... N*10h File List
+File List entries:
+ 000h 4 Offset to file data (increasing by compressed size, 4-byte aligned)
+ 004h 4 Filesize in bytes (uncompressed size) (zero in ENDOFWAD file)
+ 008h 8 Filename (uppercase ASCII, zeropadded if less than 8 chars)
+
+Folders
+The directory can contain names like F_START, F_END, P1_START, P1_END with
+filesize=0 to mark begin/end of something; that stuff can be considered as
+subdirectories with 1- or 2-character names.
+Notes: There are also regular files with underscores which are unrelated to
+folders (eg. F_SKY01). There are also 0-byte dummy files (eg. MAP17 in first
+entry MAP17.WAD). And there's a 0-byte dummy file with name ENDOFWAD in last
+file list entry (at least, it's present versions with compression support).
+
+LZSS Decompression
+Compression is indicated by Filename[0].bit7=1. The compressed size is
+NextFileOffset-FileOffset (that requires increasing offsets in File List,
+including valid offsets for 0-byte files like F_START, F_END, ENDOFWAD).
+ @@collect_more:
+ flagbits=[src]+100h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ flagbits=flagbits SHR 1
+ if zero then goto @@collect_more
+ if carry=0 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ disp=([src]*10h)+([src+1]/10h)+1, len=([src+1] AND 0Fh)+1, src=src+2
+ if len=1 then goto @@decompress_done
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+The game engine may insist on some files to be compressed or uncompressed (so
+compression may be required even if the uncompressed data would be smaller).
+
+More info: http://doomwiki.org/wiki/WAD
+
+CDROM File Archive WAD (Cardinal Syn/Fear Effect)
+-------------------------------------------------
+
+.WAD files (Cardinal Syn/Fear Effect)
+This format exists in two version:
+ Old format: Without leading Header Size entry (Cardinal Syn MagDemo03: SYN\*)
+ New format: With leading Header Size entry (eg. Fear Effect)
+Version detection could be done somewhat as so:
+ if [04h]*1Ch+8 >= [00h] then OLD version
+For loading the Old Header, one must guess the max header size (4000h should
+work, in fact, most or all Old Headers seem to be max 800h), or load more data
+on the fly as needed.
+ 000h (4) Header Size (including folder/type/file directories) (new version)
+ ... 4 Number of Folders
+ ... .. Folder List (root)
+ ... .. Type Lists (for each folder)
+ ... .. File Lists (for each folder\type)
+ ... .. File Data (for each folder\type\file)
+ Folder List Entries:
+ 000h 14h Folder name (ASCII, zeropadded)
+ 014h 4 Offset to Type List
+ 018h 4 Number of different Types in this folder
+ Type List Entries:
+ 000h 4 Offset to file entries (of same type, eg. .TIM files)
+ 004h 4 Number of file entries (of same type, eg. .TIM files)
+ 008h 4 Sum of all Filesizes with that type
+ 00Ch 4 Group Type (0000000xh)
+ File List entries (Files within Type list):
+ 000h 14h Name (ASCII, terminated by 00h, plus garbage padding)
+ 014h 4 Offset to File Data (seems 4-byte aligned... always?)
+ 018h 4 File Type (000x00xxh)
+ 01Ch 4 Filesize in bytes ;\maybe compressed/uncompressed, or rounded,
+ 020h 4 Filesize in bytes ;/always both same
+Note: The Type List for one folder can contain several entries with same Group
+Type, eg. Fear Effect GSHELLE.WAD\CREDIT has 5 type list entries (with
+2xGroup0, 2xGroup1, 1xGroup2).
+
+The Type List, Group Type and File Type stuff seems to have no function, apart
+from faster look up (the types are also implied in the filename extension).
+Except, Fear Effect .RMD .VB .VH have some unknown stuff encoded in File Type
+bit16-19.
+Group Type is usually 0 (except for .TIM .VB .VH .MSG .SPU .OFF).
+The .TIM .VB .VH .SEQ files are using standard Sony file formats. The .PMD file
+seems to be also Sony standard (except that it contains a 00000000h prefix,
+then followed by the 00000042h PMD format ID).
+
+Cardinal Syn Types
+ .BGD FileType=00000001h
+ .ANM FileType=00000003h
+ .TIM FileType=00000004h (GroupType=1)
+ .SP2 FileType=00000005h
+ .PMD FileType=00000007h
+ .MOV FileType=00000008h
+ .SPR FileType=0000000Ch
+ .PVT FileType=0000000Dh
+ .DB FileType=0000000Eh
+ .VH FileType=00000010h (GroupType=1) ;only in OLDER demo version MagDemo03
+ .VB FileType=00000011h (GroupType=1)
+ .MSG FileType=00000012h (GroupType=1) (actually, this is .TIM, too)
+ .KMD FileType=00000013h
+ .OC FileType=00000018h
+ .EMD FileType=00000019h
+ .COL FileType=0000001Bh
+ .CF FileType=0000001Ch
+ .CFB FileType=0000001Dh
+ .CL FileType=0000001Eh
+ .SPU FileType=0000001Fh (GroupType=1) ;added in newer demo version MagDemo09
+ .OFF FileType=00000020h (GroupType=1) ;added in newer demo version MagDemo09
+ .RCT FileType=00000021h ;added in newer demo version MagDemo09
+
+Fear Effect Types
+ .TIM FileType=00000000h (GroupType=1)
+ .RMD FileType=000x0001h
+ .DB FileType=00000002h
+ .ANM FileType=00000003h
+ .SYM FileType=00000004h
+ .VB FileType=000x0008h (GroupType=1)
+ .SEQ FileType=00000010h
+ .BIN FileType=00000012h
+ .SFX FileType=00000013h
+ .VH FileType=000x0014h (GroupType=2)
+ .TM FileType=00000015h
+ .NRM FileType=00000017h
+ .WPD FileType=00000018h
+
+CDROM File Archive DIR/DAT (One/Viewpoint)
+------------------------------------------
+
+DIR/DAT (One/Viewpoint)
+ Used by One (DATAFILE.BIN and DIRFILE.BIN)
+ Used by Viewpoint (VIEW.DAT and VIEW.DIR)
+Format of the DIR file:
+ 000h 60h Extension List (20h x 3-char ASCII, zeropadded if shorter than 3)
+ 060h .. Root Directory (can contain folders and files)
+ ... .. Child Directories (can contain files) (maybe also sub-folders?)
+Extension List contains several uppercase 3-character ASCII extensions, in a
+hex editor this will appear as a continous string of gibberish (dots=00h):
+ In Viewpoint: "...VCSVCFBINTXTVH.VB.STRST1ST2ST3......//..."
+ In One: "...VCTVCKSNDBINCPEINI..................//..."
+Directory Entries contain bitstreams with ASCII characters squeezed into 6bit
+values:
+ 000h 1 Length of Filename and Extension index
+ bit7-3 File Extension Index (0..1Fh = Offset I*3 in DIR file)
+ bit2-0 Filename Length-1 (0..7 = 1..8 chars)
+ 001h .. Filename in 6bit chars (N*6+7/8 bytes = 1..6 bytes for 1..8 chars)
+ bit7-2 1st character, whole 6bit ;\1st byte
+ bit1-0 2nd character, upper 2bit (if any) ;/
+ bit7-4 2nd character, lower 4bit (if any) ;\2nd byte (if any)
+ bit3-0 3rd character, upper 4bit (if any) ;/
+ bit7-6 3rd character, lower 2bit (if any) ;\3rd byte (if any)
+ bit5-0 4th character, whole 6bit (if any) ;/
+ bit7-2 5th character, whole 6bit (if any) ;\4th byte (if any)
+ bit1-0 6th character, upper 2bit (if any) ;/
+ bit7-4 6th character, lower 4bit (if any) ;\5th byte (if any)
+ bit3-0 7th character, upper 4bit (if any) ;/
+ bit7-6 7th character, lower 2bit (if any) ;\6th byte (if any)
+ bit5-0 8th character, whole 6bit (if any) ;/
+ bitN-0 Zeropadding in LSBs of last byte ;-zeropadding
+ The 6bit characters codes are:
+ 00h..09h="0..9", 0Ah..23h="a..z", 24h="_", 25h..3Fh=Unused
+ ... 4 Filesize and End Flag
+ bit31 End of Directory Flag (0=Not last entry, 1=Last entry)
+ bit30-0 Filesize 31bit (or 0=Child Folder)
+ ... 4 Offset and fixed bit
+ bit31 Unknown (always 1)
+ bit30-0 File Offset in DAT file (or Folder offset in DIR file)
+
+CDROM File Archive Darkworks Chunks (Alone in the Dark)
+-------------------------------------------------------
+
+Alone in the Dark The New Nightmare (FAT.BIN\*)
+The files in FAT.BIN are using a messy chunk format: There's no clear ID+Size
+structure. There are 7 different chunk types (DRAM, DSND, MIDB, G3DB, VRAM,
+WEAP, HAND), each type requires different efforts to compute the chunk size.
+
+VRAM Chunks (Texture/Palette) (in various files)
+ 000h 4 ID "VRAM"
+ 004h 4 With Tags (0=No, 1=Yes) (or "DRAM" when empty 4-byte chunk)
+ 008h (4) Number of Tagged items (N) (0=None) ;\only when [4]=1
+ 00Ch N*10h Tagged Item(s) ;/(not so in LEVELS\*\VIEW*)
+ ... .. Scanline Rows(s)
+ ... 4 End code (00000000h) (aka final Scanline Row with width=0)
+ Tagged Item(s) (IMG, LINE, GLOW, FLARE, BALLE, BLINK, COURIER7, BMP_xxx):
+ 000h 8 Tag (ASCII, if less than 8 chars: terminate by 00h, pad by FDh)
+ 008h 8 Data
+ Scanline Row(s) (bitmap scanlines and palette data):
+ 000h 4 Header (bit0-8=Width, bit10-18=Y, bit20-29=X, bit9,19,30,31=?)
+ 004h W*2 Data (Width*2 bytes, to be stored at VRAM(X,Y))
+Empty VRAM chunks can be either 4 or 10h bytes tall. The 4-byte variant is
+directly followed by another chunk name (eg. "VRAMDRAM"), the 10h-byte variant
+contains four words ("VRAM",WithTags=1,NumTags=0,EndCode=0).
+Note: Some files contain two VRAM chunks (eg. LEVELS\*\VIEW*).
+
+G3DB Chunks (Models) (in various files)
+ 000h 4 ID "G3DB"
+ 004h 4 Unknown (0, 1, or 2)
+ 008h 4 Size of Data part (SIZ)
+ 00Ch 4 Number of List entries (eg. 6 or 0Ah or 117Ch) (N)
+ 010h SIZ Data (supposedly LibGDX models in G3DB format)
+ ... N*4 List
+
+DRAM Chunks (Text and Binary data) (in various files)
+ 000h 4 ID "DRAM"
+ 004h 4 Size of Data part (SIZ) (can be odd)
+ 008h 4 Number of List entries (N)
+ 00Ch SIZ Data (raw data, and/or tags TEXT, SPC, COURIER7)
+ ... N*4 List
+
+WEAP Chunks (Weapons) (in WEAPON\*\*)
+ 000h 4 ID "WEAP"
+ 004h 4 Size-10h?
+ 008h .. Data
+Followed by VRAM and DSND chunks.
+
+HAND Chunks (Hands) (in LEFTHAND\*\HAND*)
+ 000h 4 ID "HAND"
+ 004h 4 Size-0Ch? (18h)
+ 008h 8 Zerofilled
+ 010h 4x4 Unknown (FFh,FF00h,xF0000h,FF3232h,FF6464h,FFDCDCh,FFFFFFh,..)
+ 020h 4 Unknown (0, 1, 101h, or 201h)
+Followed by VRAM and G3DB chunks.
+
+MIDB Chunks (Music) (in MIDI\*\*)
+ 000h 4 ID "MIDB"
+ 004h 1 Unknown (0 or 1)
+ 005h 1 Number of SEQ blocks (1..4) (S)
+ 006h 1 Number of Unknown 80h-byte blocks (1..2) (U)
+ 007h U*80h Unknown Blocks (mostly FFh-filled)
+ ... S*Var SEQ Block(s)
+ ... .. VAB Block
+ SEQ Blocks:
+ Probably some MIDI sequence data, similar to Sony's .SEQ format.
+ 000h 4 Size-0Ch (can be odd)
+ 004h 8 Name (zeropadded if less than 8 chars)
+ 00Ch 4 ID "DSEQ" ;\Size
+ 010h .. Data ;/
+ VAB Blocks:
+ Apparently inspired on Sony's .VAB format (but the ID is spelled other way
+ around, Lists have variable size, and entries have different format).
+ 000h 4 ID "VABp"
+ 004h 4 Unknown (0)
+ 008h 4 Unknown (0)
+ 00Ch 4 Size of all SPU-ADPCM samples (SIZ)
+ 010h 2 Number of List 1 entries (N1)
+ 012h 2 Number of List 2 entries (N2)
+ 014h 2 Number of Samples (N3)
+ 016h 6 Unused? (CCh-filled)
+ 01Ch N1*10h List 1
+ ... N2*10h List 2
+ ... N3*2 Sample Size List (size of each SPU-ADPCM sample)
+ ... SIZ SPU-APDCM Sample(s)
+
+DSND Chunks (Sounds) (in various files)
+ 000h 4 ID "DSND"
+ 004h 4 Unknown (0 or 2)
+ 008h .. VAB Block (same as in MIDB chunks, see there)
+
+Note
+DRAM and MIDB chunks can have odd size; there isn't any alignment padding, so
+all following chunks can start at unaligned locations.
+
+CDROM File Archive Blue Chunks (Blue's Clues)
+---------------------------------------------
+
+Blue's Clues: Blue's Big Musical (*.TXD)
+ 000h 4 Size of AUDD+SEPD+VABB chunks ;\for quick look-up only
+ 004h 4 Size of all VRAM chunks ; (can be ignored by chunk crawlers)
+ 008h 4 Size of STGE+ANIM+FRAM chunks ;/(note: sum is total filesize-0Ch)
+ ... .. AUDD Chunk (contains .VH) ;\
+ ... .. SEPD Chunk(s) (contains .SEP) ; sound
+ ... .. VABB Chunk (contains .VB) ;/
+ ... (..) VRAM Chunk(s) (not in IN\FE2.TXD) ;-textures/palettes
+ ... (..) STGE Chunk (if any, not in IN\FE*.TXD) ;-stage data?
+ ... (..) ANIM Chunk (if any, not in IN\FE*.TXD) ;\animation
+ ... (..) FRAM Chunk(s) (if any, not in IN\FE*.TXD) ;/
+ ... (..) Further groups with ANIM+FRAM Chunks (if any) ;-more animation(s)
+ AUDD Chunks:
+ 000h 4 Chunk ID ("AUDD")
+ 004h 4 Chunk Size (of whole chunk from Chunk ID and up)
+ 008h 4 Compression Flag (0=Uncompressed)
+ 00Ch 4 Zero
+ 010h .. VH File (Sony Voice Header, starting with ID "pBAV")
+ SEPD Chunks:
+ 000h 4 Chunk ID ("SEPD")
+ 004h 4 Chunk Size (of whole chunk from Chunk ID and up)
+ 008h 4 Compression Flag (0=Uncompressed)
+ 00Ch 2 Zero
+ 00Eh 2 Number of sequences (in the SEP sequence archive)
+ 010h 4 Zero
+ 014h .. SEP File (Sony Sequence archive, starting with ID "pQES")
+ ... .. Zeropadding to 4-byte boundary
+ VABB Chunks:
+ 000h 4 Chunk ID ("VABB")
+ 004h 4 Chunk Size (of whole chunk from Chunk ID and up)
+ 008h 4 Compression Flag (0=Uncompressed)
+ 00Ch .. VB File (Sony Voice Binary, with raw SPU-ADPCM samples)
+ VRAM Chunks:
+ 000h 4 Chunk ID ("VRAM")
+ 004h 4 Chunk Size (of whole chunk from Chunk ID and up)
+ 008h 4 Compression Flag (1=Compressed)
+ 00Ch 2 VRAM.X
+ 00Eh 2 VRAM.Y
+ 010h 2 Width in halfwords
+ 012h 2 Height
+ 014h 4 Decompressed Size (Width*Height*2) ;\Texture Bitmaps 8bpp
+ 018h .. Compressed Data ; (or Palettes, in last VRAM
+ ... .. Zeropadding to 4-byte boundary ;/chunk)
+ STGE Chunks:
+ 000h 4 Chunk ID ("STGE")
+ 004h 4 Chunk Size (of whole chunk from Chunk ID and up)
+ 008h 4 Compression Flag (0=Uncompressed)
+ 00Ch .. Unknown (stage data?)
+ ANIM Chunks:
+ 000h 4 Chunk ID ("ANIM")
+ 004h 4 Chunk Size (of whole chunk from Chunk ID and up)
+ 008h 4 Compression Flag (0=Uncompressed)
+ 00Ch .. Unknown (animation sequence info?)
+ FRAM Chunks:
+ 000h 4 Chunk ID ("FRAM")
+ 004h 4 Chunk Size (of whole chunk from Chunk ID and up)
+ 008h 4 Compression Flag (0=When Chunksize=14h, 1=When Chunksize>14h)
+ 00Ch 1 Width in bytes
+ 00Dh 1 Height
+ 00Eh 6 Unknown, looks like three signed 16bit values (maybe X,Y,Z)?
+ 014h (4) Decompressed Size (Width*Height*1) ;\Animation Frame Bitmap 8bpp
+ 018h (..) Compressed Data ; (only if Chunksize>14h)
+ ... (..) Zeropadding to 4-byte boundary ;/
+VRAM and FRAM chunks with [08h]=1 (and Chunksize>14h) are compressed:
+--> CDROM File Compression Blues
+
+CDROM File Archive HED/CDF (Parasite Eve 2)
+-------------------------------------------
+
+Crazy Data Format (CDF) is used by Parasite Eve 2, on Disc 1 and 2:
+1: PE_Disk.01 Stage0.hed Stage0.cdf Stage1.cdf Stage2.cdf Stage3.cdf Inter0.str
+2: PE_Disk.02 Stage0.hed Stage0.cdf Stage3.cdf Stage4.cdf Stage5.cdf Inter1.str
+
+STAGE0.HED and STAGE0.CDF
+This uses separate header/data files. The directory is stored in STAGE0.HED:
+ 0000h 78h Streaming List (03h entries, 28h-bytes each, all entries used)
+ 0078h 1B00h File List (360h entries, 8 bytes each, all entries used)
+ 1B78b 8 File List End Code (FFFFFFFFh,FFFFFFFFh)
+The actual data for the files (and audio stream) is stored in STAGE0.CDF.
+
+STAGE1.CDF .. STAGE5.CDF
+ 0000h 800h Root: Folder List (100h entries, 8-byte each, unused=zeropadded)
+ 0800h .. 1st Folder (File/Streaming List and Data)
+ ... .. 2nd Folder (File/Streaming List and Data)
+ ... .. etc.
+Folder List entries:
+ 000h 4 Folder ID (usually N*100+1 decimal, increasing, eg. 101,201,301,etc.)
+ 004h 4 Folder Size/800h (of whole folder, with File/Stream List and Data)
+ The Folder List ends with unused/zeropadded entries with ID/Size=00000000h.
+Folder format:
+ 0000h 510h File List (A2h entries, 8-bytes each, unused=zeropadded)
+ 0510h 4 Zero (padding to decimally-minded offset 1300 aka 514h)
+ 0514h 2D0h Streaming List (12h entries, 28h-bytes each, unused=zeropadded)
+ 07E4h 1Ch Zero (padding to end of sector)
+ 0800h ... Data (for Files, Audio streams, and sometimes also Movie streams)
+
+File List entries (in STAGE0 and STAGE1-5)
+ 000h 4 File ID (increasing, eg. 0,1,2,3,4,etc.) (or 99) (or N*100+x)
+ 004h 4 File Offset/800h in in .CDF (from begin of current Folder)
+For STAGE0, file list ends with ID/Offset=FFFFFFFFh at end of HED file. For
+STAGE1-5, file list ends with unused/zeropadded entries with
+ID/Offset=00000000h.
+The filesize can be computed as "NextOffset-CurrOffset" (at 800h-byte
+resolution). Whereas, "NextOffset" can be:
+ The offset of next File in File List (same as CurrOffset for 0-byte files)
+ The offset of next Audio stream in Streaming List
+ The offset of next Movie stream in Streaming List (if it's in .CDF, not .STR)
+ The size of the current Folder (for STAGE1-5)
+ The size of the whole .CDF file (for STAGE0)
+For STAGE1-5, audio streams are usually stored at the end of folder (after the
+files). However, for STAGE0, audio streams are oddly inserted between file21000
+and file30100.
+
+File Chunks (for files within File List)
+Most CDF files in STAGE0 and STAGE1-5 do contain one or more chunks with
+10h-byte chunk headers (this can be considered as an additional filesystem
+layer, with the chunk data being the actual files).
+ 000h 1 Chunk Type (see below)
+ 001h 1 End Flag (01h=More Chunks follow, FFh=Last Chunk)
+ 002h 2 Unknown (usually 800h, sometimes 500h or 600h)
+ (eg. 500h in stage0\file30301\chunkX)
+ (eg. 600h in stage1\folder1201\file0\chunkXYZ)
+ 004h 4 Chunk Size/800h
+ 008h 4 Unknown (usually zero) (or 80xxxx00h in Chunk Type 0 files?)
+ 00Ch 4 Zero (0)
+ 010h .. Data (Chunk Size-10h bytes)
+Chunk Types:
+ 00h=Room package .pe2pkg
+ 01h=Image .pe2img
+ 02h=CLUT .pe2clut
+ 04h=CAP2 Text .pe2cap2
+ 05h=Room backgrounds .bs
+ 06h=SPK/MPK music program .spk ;stereo/mono, sound/music, single/multiple?
+ 07h=ASCII text .txt (eg. stage0\20101..20132)
+ ;Reportedy also (but wrong):
+ ;60h=Sounds .pe2snd (but nope, that's wrong, see below)
+ ;60h is a MDEC movie from Streaming List (unrelated to File List chunks),
+ ;60h is 20h-byte .STR header each 800h-bytes (occurs in "stage1\folder501")
+There are some chunkless files:
+ stage0\40105...40198 are raw hMPK files without chunks
+ stage0\11000, 20213, 20214, 20300, .., 660800 and 900000 are empty 0-byte
+
+Streaming List Movie entries (stream type 1)
+ 000h 2 Stream Type (0001h=Movie)
+ 002h 2 Unknown (8000h or 0000h)
+ 004h 4 Offset/800h in current Folder of .CDF file ;<-- used when [024h]=0
+ 008h 4 Offset/800h in INTERx.STR file ;<-- used when [024h]>0
+ 00Ch 2 Unknown (0000h)
+ 00Eh 2 Stream ID (increasing, usually starting at 64h aka 100 decimal)
+ 010h 2 Stream sub.ID (usually 0, increases +1 upon multiple same IDs)
+ 012h 2 Picture Width (0140h = 320 decimal)
+ 014h 2 Picture Height (00F0h = 224 decimal)
+ 016h 2 Unknown (0000h)
+ 018h 2 Unknown (0000h or 0018h) maybe 24bpp or 24fps
+ 01Ah 2 Unknown (73Ah or 359h or 3DCh) (Size? but it's slighty too large?)
+ 01Ch 6 Unknown (zero)
+ 022h 2 Unknown (0 or 1) (often 1 when [024h]>0, but not always)
+ 024h 2 Movie number in INTERx.STR, 1 and up? (or 0=Movie is in STAGEx.CDF)
+ 026h 2 Unknown (0 or 1)
+The size of movie streams in .CDF can be computed in similar fashion as for
+File List entries (see there for details).
+The size of movie streams in .STR cannot be computed easily (the next stream
+isn't neccassarily stored at the next higher offset; even if it's within same
+folder). As workaround, one could create a huge list with all streams from all
+Folders in all STAGEx.CDFs (or scan the MDEC .STR headers in .STR file; and
+check when the increasing frame number wraps to next stream).
+The dual offsets are oddly computed as: [004h]=[008h]+EndOfLastFileInFolder
+(that gives the correct value in the used entry, and a nonsensical value in the
+other entry).
+
+Streaming List Audio entries (stream type 2)
+ 000h 2 Stream Type (0002h=Audio)
+ 002h 2 Unknown (806Ah or increasing 0133h,0134h,0135h)
+ 004h 4 Offset/800h in STAGEx.CDF file (increasing offsets)
+ 008h 4 Unknown (0 or 13000h or E000h)
+ 00Ch 2 Stage Number (0..5 = STAGE0-5)
+ 00Eh 2 Stream ID (1, or increasing 3Ah,3Bh,3Ch)
+ 010h 4 Stream sub.ID (usually 0Bh, increases +0Ah upon multiple same IDs)
+ 014h 2 Unknown (0 or 2B0h or 3ADh or 398h) (Size/800h minus something?)
+ 016h 2 Unknown (usually 20h, sometimes 0Fh)
+ 018h 4 Unknown (2 or 1) ... maybe num channels ?
+ 01Ch 2+2 Unknown (0,0 or 800h,800h)
+ 020h 8 Unknown (0)
+The size of audio streams can be computed in similar fashion as for File List
+entries (see there for details).
+
+Audio Stream Data (stored alongsides with file data in STAGEx.CDF file)
+This contains a 800h-byte header a list of 32bit indices:
+ 000h 800h Whatever increasing 32bit index/timing values? FFFFFFFFh=special?
+ ;That header exists in stage0\ and stage3\folder101\
+ ;That header doesn't exist in all files (eg. not in stage1\folder301\)
+then followed by several chunk-like STM blocks with 10h-byte headers:
+ 000h 4 Chunk Index (increases each second chunk, from 0 and up)
+ 004h 4 Number of Chunk Indices
+ 008h 4 Fixed (02h,"STM") ;2-channel Stream?
+ 00Ch 1 Chunk Subindex (toggles 00h or 01h per each chunk) ;ch left/right?
+ 00Dh 1 Chunk Size/800h
+ 00Eh 4 Unknown (can be 00h, 01h, 11h, 20h, 21h)
+ 00Fh 4 Unknown (can be A0h or C0h)
+ 010h .. Data (Chunk Size-10h bytes) (looks like SPU-ADPCM audio)
+After the last STM chunk, there is more unknown stuff:
+ 000h 0 Number of ADPCM blocks? (eg. 28h or 49h)
+ 004h 4 Size of extra data block in bytes (eg. 13900h or 24200h)
+ 008h 38h Zerofilled
+ 040h 8 Zerofilled (maybe 1st sample of 1st SPU-ADPCM block)
+ 048h .. Looks like more SPU-ADPCM block(s), terminated by ADPCM end flag(s)
+ ... .. Zerofilled (padding to end of last 800h-byte sector)
+
+Movie Stream Data (stored in .CDF, or in separate INTERx.STR file)
+The movies are usually stored in INTERx.STR (except, some have them stored in
+STAGEx.CDF, eg. stage1\folder501, stage1\folder801, stage2\folder2101,
+stage2\folder3001).
+The data consists of standard .STR files (with 20h-byte headers on each
+800h-byte sector), with the MDEC data being in huffman .BS format (with .BS
+header... per frame?).
+And, supposedly interleaved with XA-ADPCM audio sectors...?
+
+PE_DISK.01 and PE_DISK.02
+The presence of these files is probably used to detect which disc is inserted.
+The file content is unknown (looks like 800h-byte random values).
+
+Note
+Reportedly "Files inside archive may be compressed with custom LZSS
+compression" (unknown if/when/where/really/which files).
+
+CDROM File Archive IND/WAD (MTV Music Generator)
+------------------------------------------------
+
+MTV Music Generator (IND/WAD) (MagDemo30: JESTER\WADS\ECTS.IND and .WAD)
+ECTS.IND contains FOLDER info:
+ 0000h 20h Name/ID ("Music 2", zeropadded)
+ 0020h 4 Unknown (110000h)
+ 0024h 4 Filesize-1000h (size excluding last 1000h-byte padding)
+ 0028h 4 Unknown (17E0h)
+ 002Ch 4 Unknown (5)
+ 0030h N*10h Folder List, starting with Root in first 10h-byte
+ 2CF0h 4 Small Padding (34h-filled)
+ 2CF4h 1000h Final Padding (34h-filled)
+ Folder List entries that refer to Child Folders in ECTS.IND:
+ 000h 8 Folder Name ("EXTRA*~*", zeropadded if less than 8) ("" for root)
+ 008h 2 Self-relative Index to first Child folder (positive)
+ 00Ah 2 Number of Child Folders (0..7FFFh)
+ 00Ch 4 Always 0007FFFFh (19bit Offset=7FFFFh, plus 13bit Size=0000h)
+ Folder List entries that refer to File Folders in ECTS.WAD:
+ 000h 8 Folder Name ("EXTRA*~*", zeropadded if less than 8)
+ 008h 2 Self-relative Index to Parent folder (negative)
+ 00Ah 2 Number of Child Folders (always 8000h=None)
+ 00Ch 4 Offset and Size in ECTS.WAD
+ The 32bit "Offset and Size" entry consists of:
+ 0-18 19bit Offset/800h in ECTS.WAD
+ 19-31 13bit Size/800h-1 in ECTS.WAD
+ECTS.WAD contains FILE info and actual FILE data:
+ There are several File Folders (at the locations specified in ECTS.IND).
+ The separate File Folders look as so:
+ 000h 4 Number of files (N)
+ 004h N*10h File List
+ ... .. 34h-Padding to 800h-byte boundary
+ ... .. File Data area
+ File List entries:
+ 000h 8 File Name ("NAMELIST", "ACIDWO~1", etc.) (00h-padded if shorter)
+ 008h 4 Offset/800h (always from begin of WAD, not from begin of Folder)
+ 00Ch 4 Filesize in bytes
+ The first file in each folder is called "NAMELIST" and contains this:
+ 000h 20h Long Name for Parent Folder (eg. "Backgrounds", zeropadded)
+ 020h 20h Long Name for this Folder (eg. "Extra 1", zeropadded)
+ 040h N*20h Long Names for all files in folder (except for NAMELIST itself)
+ For example, Long name for "ACIDWO~1" would be "Acidworld". Short names are
+ uppercase, max 8 chars, without spaces (with "~N" suffix if the long name
+ contains spaces or more than 8 chars). Many folder names are truncated to
+ one char (eg. "D" for Long name "DTex"), in such cases short names CAN be
+ lowercase (eg. "z" for Long name "zTrans").
+ The Long Names are scattered around in the NAMELIST files in ECTS.WAD file,
+ so they aren't suitable for lookup (unless when loading all NAMELIST's).
+
+CDROM File Archive GAME.RSC (Colonly Wars Red Sun)
+--------------------------------------------------
+
+Colony Wars Red Sun (MagDemo31: CWREDSUN\GAME.RSC, 13Mbyte)
+ 0000h 4 Offset to Bonkers List (2794h)
+ 0004h F*8 Folder List (80h bytes, 10h entries)
+ 0084h N*14h File List(s) for each folder (2710h bytes, 1F4h entries)
+ 2794h 4 Number of Bonkers (FE3h)
+ 2798h B*8 Bonkers List (7F18h bytes, FE3h entries)
+ A6B0h 8 Unknown (zerofilled)
+ A6B8h .. File Data area
+Folder List entries:
+ 000h 4 Offset to File List for this folder ;\both zero when empty
+ 004h 4 Number of Files in this folder ;/
+File List entries:
+ 000h 10h Filename ("FILENAME_EXT", zeropadded)
+ 010h 3 Index (in Bonkers list) (000h..Fxxh)
+ 013h 1 Folder Number where the file is stored (00h..0Fh)
+Bonkers List entries:
+ 000h 4 File Offset (to Data, inreasing, 4-byte aligned, A6B8h and up)
+ 004h 4 Folder Number where the file is stored (00h..0Fh)
+Offsets/Indices in Folder/File list are unsorted (not increasing).
+Offsets in Bonkers List are increasing (so filesizes can be computed as
+size=next-curr, except, the LAST file must be computed as size=total-curr).
+There is no "number of folders entry" nor "folder list end marker", as
+workaround, while crawling the folder list, search the smallest file list
+offset, and treat that as folder list end offset.
+In the demo version, all File List entries for Folder 5 are pointing to files
+with filesize=0, however, the Bonkers List has a lot more "hidden" entries that
+are marked to belong to Folder 5 with nonzero filesize.
+Note: Older Colony Wars titles did also have a GAME.RSC file (but in different
+format, without folder structure).
+
+CDROM File Archive BIGFILE.DAT (Soul Reaver)
+--------------------------------------------
+
+Legacy of Kain: Soul Reaver - BIGFILE.DAT
+Legacy of Kain: Soul Reaver (MagDemo26: KAIN2\BIGFILE.DAT)
+ 000h 2 Number of Folders (175h in retail, 0Ah in demo)
+ 002h 2 Zero
+ 004h N*8 Folder List (8-byte per Folder)
+ ... .. Zeropadding (to 800h-byte boundary)
+ ... .. 1st Folder (with File List, and File Data for that folder)
+ ... .. 2nd Folder (with File List, and File Data for that folder)
+ ... .. 3rd Folder (with File List, and File Data for that folder)
+ ... .. etc.
+Folder List entries:
+ 000h 2 Unknown (somehow randomly increases from -8000h to +7E8Fh)
+ 002h 2 Number of Files in this Folder (eg. 97h)
+ 004h 4 Offset to Folder (usually 800h-aligned)
+Folder format:
+ 000h 2 Number of Files (same value as FolderistEntry[002h]) ;\encrypted
+ 002h 2 Zero ; by 16bit
+ 004h N*10h File List (10h-byte per Folder) ; XOR value
+ ... .. Zeropadding (to 800h-byte boundary) ;/
+ ... .. File Data for this folder ;-unencrypted
+File List entries:
+ 000h 4 Unknown (random? filename hash? encrypted name?)
+ 004h 4 File Size in bytes
+ 008h 4 File Offset (usually 800h-aligned)
+ 00Ch 4 Unknown (random? filename hash? encrypted name?)
+Encryption:
+The file header, the first some Folder headers (those in first quarter or so),
+and (all?) File Data is unencrypted (aka XORed with 0000h).
+The Folder headers at higher offsets are encrypted with a 16bit XOR value. That
+XOR value is derived from Subchannel Q via LibCrypt:
+--> CDROM Protection - LibCrypt
+When not having the Subchannel data (or when not knowing which Folders are
+encrypted or unencrypted), one can simply obtain the encryption key from one of
+these entries (which will be key=0000h when unencrypted):
+ key = FileListEntry[000h] XOR FolderListEntry[002h] ;encrypted num entries
+ key = FileListEntry[002h] ;encrypted Zero
+ key = FileListEntry[zeropadding, if any] ;encrypted Zeropadding
+LibCrypt seems to be used only in PAL games, unknown if the Soul Reaver NTSC
+version does also have some kind of encryption.
+
+CDROM File Archive FF8 IMG (Final Fantasy VIII)
+-----------------------------------------------
+
+FF8 is quite a mess without cear directory structure. Apart from SYSTEM.CNF and
+boot EXE, there is only one huge IMG file. There are at least two central
+directories: The Root directory (usually at the start of the IMG file), and the
+Fields directory (hidden in a compressed file that can be found in the Root
+directory). Moreover, there are files that exist in neither of the directories
+(most notably the Movies at the end of the IMG file).
+
+IMG File
+The IMG file doesn't have a unique file header, it can be best detected by
+checking the filename: FF8DISCn.IMG with n=1-4 for Disc 1-4 (or only
+FF8DISC1.IMG or FF8.EXE+FF8TRY.IMG for demo versions).
+The directories contain ISO sector numbers (originated from begin of the ISO
+area at sector 00:02:00). Accordingly, it's best to extract data from the whole
+disc image (in CUE/BIN format or the like). When having only the raw IMG file,
+one most know/guess the starting sector number (eg. assume that the first Root
+File is located on the sector after the Root Directory, and convert sector
+numbers ISO-to-IMG accordingly).
+Another oddity is that many files contain RAM addresses (80000000h-801FFFFFh),
+unknown how far that's relevant, and if there are cases where one would need to
+convert RAM addresses to IMG offsets.
+
+Root Directory
+The Root Directory is found at:
+ Offset 0000h in FF8DISCn.IMG in NTSC retail versions
+ Offset 2800h in FF8DISCn.IMG in PAL retail versions
+ Offset 0000h in FF8DISC1.IMG in french demo version
+ Offset ?????h in FF8.EXE in MagDemo23 (...maybe offset 3357Ch ?)
+ Offset 33510h in FF8.EXE in japanese demo version ?
+ Offset 33584h in FF8.EXE in other demo versions ?
+For detection:
+ if FF8DISCn.IMG starts with 000003xxh --> assume Root at IMG offset 0
+ if FF8DISCn.IMG starts with xxxxxxxxh --> assume Root at IMG offset 2800h
+ if FF8TRY.IMG starts with "SmCdReadCore" --> assume Root somewhere in EXE
+File List:
+ 000h N*8 File List entries
+ ... .. Zeropadding to end of 800h-byte sector
+File List entries:
+ 000h 4 ISO Sector Number (origin at 00:02:00) (unsorted, not increasing)
+ 004h 4 Filesize in bytes
+The file list does usually end with zeropadding (unknown if that applies to all
+versions; namely the Demo version might end with gibberish instead of having
+800h-byte sector padding).
+
+Fields Directory
+The Fields Directory is located in Root file 0002h. First of, decompress that
+file, then search the following byte sequences to find the start/end of the
+directory:
+ retail.start 040005241800bf8f1400b18f1000b08f2000bd270800e00300000000
+ retail.end 0000010002000300
+ demo.start 76DF326F34A8D0B863C8C0EC4BE817F8
+ demo.end 0000000000000000000000000000000000100010
+The bytes between those start/end pattern contain the Directory, with entries
+in same format as Root directory:
+ 000h 4 ISO Sector Number (origin at 00:02:00)
+ 004h 4 Filesize in bytes
+Notes: Root file 0002h is about 190Kbyte (decompressed), of which, the Fields
+Directory takes up about 8Kbytes, the remaining data contains other stuff.
+The sector numbers in the Fields Directory refer to other locations in the IMG
+file (not to data in Root File 0002h).
+
+Movie List
+There is no known central directory for the movies (unknown if such a thing
+exists, or if the movie sector numbers are scattered around, stored in separate
+files). However, a movie list can be generated by crawling the movie headers,
+starting at end of IMG file:
+ sector = NumSectors(IMG file)
+ @@lop:
+ seek(sector-1), read(buf,08h bytes)
+ if first4byte[buf+0]=("SMJ",01h), or ("SMN",01h) then
+ num_sectors=(byte[buf+5]+1)*(halfword[buf+6]+1)
+ sector=sector-num_sectors
+ AddToMovieFileList(sector, num_sectors)
+ goto @@lop
+ endif
+That should cover all movies, which are all at the end of the IMG file (except,
+there's one more movie-like file elsewhere in the middle of IMG file, that file
+has only SMN/SMR audio sectors, without any SMJ video sectors).
+
+PADBUG archives
+PADBUG archives are used in Root files 001Eh..007Fh, most of them contain two
+AKAO files (except file 004Bh contains one AKAO and one TXT file).
+ 000h 4 Number of Files (N) (usually 2)
+ 004h N*8 File List
+ ... .. File Data area
+File List entries:
+ 000h 4 Offset in bytes (increasing, 4-byte aligned, see Quirk)
+ 004h 4 File Size in bytes (can be odd)
+Quirk: All files are zeropadded with 1-4 bytes to 4-byte boundary (ie. files
+that do end on a 4-byte boundary will be nethertheless padded with 4 zeroes).
+Note: The PADBUG archives resemble LNK archives in O.D.T. (though those LNK
+archives have a different unique 4-byte padding quirk).
+
+Compression
+--> CDROM File Compression LZ5 and LZ5-variants
+FF8 does reportedly also use GZIP (unknown in which files).
+
+Known/unknown sectors for US version FF8DISC1.IMG
+ root sectors: 27CBh ;\
+ field sectors: D466h ; total known sectors: 36D13h
+ movie sectors: 270E2h ;/
+ unknown sectors: 14F49h
+ total IMG sectors: 4BC5Ch
+
+See also
+https://github.com/myst6re/deling/blob/master/FF8DiscArchive.cpp
+https://ff7-mods.github.io/ff7-flat-wiki/FF8/PlaystationMedia.html
+
+CDROM File Archive FF9 IMG (Final Fantasy IX)
+---------------------------------------------
+
+Final Fantasy IX (FF9.IMG, 320Mbyte) Overall format
+ 000h Root Directory
+ 800h 1st Child Folder
+ ... 2nd Child Folder
+ ... 3rd Child Folder
+ ... ...
+ 8000h ? Last folder, with Type3, contains 1FFh x increasing 16bit numbers
+ ... Data for files in 1st Child Folder
+ ... Data for files in 2nd Child Folder
+ ... Data for files in 3rd Child Folder
+ ...
+
+IMG Root Directory
+ 000h 4 ID "FF9 "
+ 004h 4 Unknown (06h on Disc 1 of 4) (maybe version, or disc id?)
+ 008h 4 Number of Folder List entries (0Fh)
+ 00Ch 4 Unknown (01h on Disc 1 of 4) (maybe version, or disc id?)
+ (or Offset/800h to first file list?)
+ 010h N*10h Folder List
+ ... .. Padding to 800h-byte boundary ("FF9 FF9 FF9 FF9 ")
+Folder List entries:
+ 000h 4 FolderType (2=Normal, 3=Special, 4=Last entry)
+ 004h 4 Number of entries in File List (0..1FFh ?)
+ 008h 4 Offset/800h to Child Folder with File List
+ 00Ch 4 Offset/800h to File Data (same as 1st offs in File List) (0=Last)
+
+IMG Child Folders (FolderType=2)
+ 000h N*8 File List entries (N=Number of files, from Root directory)
+ N*8 8 File List END entry (ID=FFFFh, Attr=FFFFh, Offs=EndOfLastFile)
+ ... .. Zeropadding to 800h-byte boundary
+File List entries:
+ 000h 2 File ID (increasing, often decimal 0,10,100, or FFFFh=Last)
+ 002h 2 Attr (unknown purpose, eg. 0,2,3,4,8,21h,28h,2Fh,44h,114h,FFFFh)
+ 004h 4 Offset/800h to File Data (increasing, implies end of prev entry)
+
+IMG Child Folders (FolderType=3)
+ 000h N*2 File Offsets/800h, from File Data Offset in Root (or FFFFh=None)
+ N*2 2 End Offset for last file
+The filesize can be computed as (NextOffs-CurrOffs)*800h, however, one must
+skip unused entries (FFFFh) to find NextOffs.
+
+Nested Child Archives
+Most of the files in FF9.IMG are DB archives, there are also some DOT1
+archives.
+--> CDROM File Archive FF9 DB (Final Fantasy IX)
+There are various combinations of IMG, DB, DOT1 archives nested up to 4 levels
+deep:
+ IMG\DOT1 (eg. dir01\file003C)
+ IMG\DB (eg. dir01\file2712)
+ IMG\DB\DOT1 (eg. dir01\file2712\00-0411)
+ IMG\DB\DOT1\DOT1 (eg. dir01\file2712\00-0443\*)
+ IMG\DB\DB (eg. dir03\file2328\1B-000*)
+
+Folders in Root directory
+ dir00 - Status/Menu/Battle/... -Text and random stuff.
+ dir01 - Misc Images (Logos, Fonts, World 'mini' Map images, etc).
+ dir02 - Dialog Text
+ dir03 - Map models (Mini-zidane, airships, save point moogle, tent...)
+ dir04 - Field models
+ dir05 - Monster Data (Part I, stats, names, etc).
+ dir06 - Location Data (Dungeon, Cities, etc).
+ dir07 - Monster Data (Part II, 3d models)
+ dir08 - Weapon Data (including models)
+ dir09 - Samplebanks and Sequencer Data (ie music).
+ dir0A - party members Data (including models)
+ dir0B - Sound effects
+ dir0C - World Map Data
+ dir0D - Special effects (magic, summons...)
+
+See also
+https://ninjatoes.blogspot.com/2020/07/
+https://wiki.ffrtt.ru/index.php?title=Main_Page
+
+CDROM File Archive GTFS (Gran Turismo 2)
+----------------------------------------
+
+Gran Turismo 2 (MagDemo27: GT2\GT2.VOL, GT2.VOL\arcade\arc_carlogo) - GTFS
+ 000h 4 ID "GTFS" ;\
+ 004h 4 Zero ;
+ 008h 2 Number of 4-byte File Offset List entries (N) ; File(0)
+ 00Ah 2 Number of 20h-byte File/Folder Name List entries (F) ;
+ 00Ch 4 Zero ;
+ 010h N*4 File Offset List (see below) ;/
+ ... .. Zeropadding to 800h-byte boundary
+ ... F*20h File/Folder Name List (see below) ;-File(1)
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. File Data ;-File(2)
+ ... .. Zeropadding to 800h-byte boundary
+ ... File Data ;-File(3)
+ ... .. ...
+ ... File Data ;-File(N-2)
+ ... .. Zeropadding to 800h-byte boundary
+ EOF 0 End of File ;-File(N-1)
+That is, for N files, numbered File(0)..File(N-1):
+ File(0) and File(1) = Directory information
+ File(2)..File(N-2) = Regular data files
+ File(N-1) = Offset List entry points to the end of .VOL file
+File Offset List entries, in File(0):
+Contains information for all files, including File(0) and File(1), and
+including an entry for File(N-1), which contains the end offset for the last
+actual file, ie. for File(N-2).
+ Bit0-10 = Number of padding bytes in last sector of this file (0..7FFh)
+ Bit11-31 = Offset/800h to first sector of this file (increasing)
+ To compute the filesize: Size=(Entry[N+1] AND FFFFF800h)-Entry[N]
+File/Folder Name List entries, in File(1):
+Contains information for all files, excpet File(0), File(1), File(N-1), plus
+extra entries for Folders, plus ".." entries for links to Parent folders.
+ 000h 4 Unknown (379xxxxxh) (maybe timestamp?)
+ 004h 2 When Flags.bit0=0: Index of File in File Offset List (2 and up)
+ When Flags.bit0=1: Index of first child in Name List, or...
+ When Flags.bit0=1: Index of 1st? parent in Name List (Name="..")
+ 006h 1 Flags (bit0:0=File, 1=Directory; bit7:1=Last Child entry)
+ 007h 19h Name (ASCII, zeropadded)
+The game does use several archive formats: GTFS (including nested GTFS inside
+of main GTFS) and WAD.WAD and DOT1.
+The game does use some GT-ZIP compressed files, and many GZIP compressed files
+(albeit with corrupted/zeropadded GZIP footers; due to DOT1 filesize 4-byte
+padding and (unneccessarily) GTFS 800h-byte padding).
+--> CDROM File Compression GT-ZIP (Gran Turismo 1 and 2)
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+To extract the decompressed size from the corrupted GZIP footers, one could
+compute the compressed "size" (excluding the GZIP header, footer, and padding),
+and search for a footer entry that is bigger than "size".
+ size=gz_filesize
+ size=size-GzipHeader(including ExtraHeader, Filename, Comment, HeaderCrc)
+ size=size-GzipFooter(8) ;initially assuming 8-byte footer (without padding)
+ i=gz_filesize-4
+ @@search_footer:
+ if buf[i]<size then i=i-1, size=size-1 goto @@search_footer
+ decompressed_size = buf[i]
+Note: Above doesn't recurse the worst-case compression ratio, where compressed
+files could be slightly bigger than decompressed files.
+
+CDROM File Archive Nightmare Project: Yakata
+--------------------------------------------
+
+Nightmare Project: Yakata
+ISO Files:
+ CD.IMG 550Mbyte Contains file 004h..FFFh
+ CDRTBL.DAT 32Kbyte Alias for file 000h (File List for file 000h..FFFh)
+ FDTBL.DAT 2Kbyte Alias for file 001h (Folder List and Disc ID)
+ SLPS_010.4* 500Kbyte Alias for file 003h (Boot EXE)
+ SYSTEM.CNF 72bytes Alias for file 002h (Boot Info)
+ XXXXXXXX. 27Mbyte Padding (zerofilled)
+FDTBL.DAT (Folder List):
+ FDLTBL.DAT seems to be used to divide the file list in CDRTBL.DAT into
+ separate folders. The Folder List entries are containing the first file number
+ for each folder. Empty folders have same file number as next entry.
+ The last folder contains the specified file number plus all remaining files.
+ 000h 56h*2 Folder List (16bit File Numbers, increasing from 0004h to 0xxxh)
+ 0ACh 748h Zerofilled
+ 7F4h 0Ah Game ID (ASCII "SLPS1045",00h,00h; always so on Disc 1..3)
+ 7FEh 2 Disc ID (1..3 = Disc 1..3)
+CDRTBL.DAT (File List):
+ 000h 8000h File List (1000h x 8-byte entries)
+ File List entries:
+ 000h 4 Sector (MM:SS:FF:00 in BCD, increasing) ;\all zero for
+ 004h 2 Size1 (NumFramesCh1 or NumSectors) ; unused entries
+ 006h 2 Size0 (NumFramesCh0 or Zero) ;/
+ The meaning of the Size entries depends on the file type:
+ Normal binaries: [004h]=NumSectors [006h]=0 (1 channel)
+ XA-ADPCM streams: [004h]=NumSectors-50h [006h]=0 (16 channels)
+ MDEC streams: [004h]=NumFrames [006h]=0 (audio+video)
+ Special streams: [004h]=NumFramesCh1 [006h]=NumFramesCh0 (2 channels)
+ To determine the actual filesize, one must compute the difference between
+ sectors for current and next used file entry (or end of CD.IMG for last file;
+ or alternately assume last file to be a Normal Binary with Size=NumSectors).
+ Normal Binaries:
+ Contains single files (file=0/channel=0). Filetypes include TIM, VB, VH,
+ other/custom file formats, and DOT1 archives.
+ The DOT1 archives have 4-byte aligned offsets, but, unconventionally, with
+ some offsets set to ZERO (usually the last entry, and sometimes also other
+ entries):
+ SEQ files (Disc1:Dir08h\File173h) ;with ZERO entries (=uncommon)
+ SEQ files (Disc1:Dir09h\File176h..3D7h) ;with ZERO entries (=uncommon)
+ SEQ files (Disc1:Dir0Ah\File3DAh..3E6h) ;with ZERO entries (=uncommon)
+ TIM files (Disc1:Dir4Fh\File962h..983h) ;with ZERO entries (=uncommon)
+ TIM files (Disc1:Dir0Ch\File414h..426h) ;without ZERO entries (=normal DOT1)
+ XA-ADPCM Streams (Disc1:Dir0Bh\File3E7h..413h):
+ These contain 16 audio streams (file=1/channel=00h-0Fh). The Size entry is
+ set to total size in sectors for all streams, minus 50h (ie. there appears
+ to be 50h sectors appended as padding before next file).
+ MDEC Streams (Disc1:Dir53h\FileBD1h..BEBh):
+ These are standard STR files with MDEC video (file=0/channel=1) and
+ XA-ADPCM (file=1/channel=1). There are 10 sectors per frame (8-9 video
+ sectors plus 1-2 audio sectors). The total filesize is NumFrames*10+Align(8)
+ sectors; the Align(8) might be there to include one final audio sector.
+ Special Streams (Disc1:Dir07h\File0E9h-16Eh and Dir50h\File985h..B58h):
+ These are custom STR files (non-MDEC format), perhaps containing Polygon
+ streams or whatever.
+ There are two channels (file=1/channel=00h-01h), each channel contains
+ data that consists of 5 sectors per frame (1xHeader plus 4xData).
+ The sectors have STR ID=0160h, and STR Type as follows:
+ 0000h=Whatever special, channel 0 header (sector 0)
+ 0400h=Whatever special, channel 1 header (sector 1)
+ 0001h=Whatever special, channel 0 data (sector 2,4,6,8)
+ 0401h=Whatever special, channel 1 data (sector 3,5,7,9)
+ The File List size entries contain Number of Frames for each channel (either
+ of these entries may be zero, or bigger/smaller/same than the other entry).
+ The smaller channel is padded to same size as bigger channel (ie. total
+ filesize is "max(NumFramesCh0,NumFramesCh1)*10 sectors"; though that formula
+ doesn't always hold true, for example, Disc1:Dir50h\FileA2Dh and FileB1Bh
+ are bigger or smaller than expected).
+
+CDROM File Archive FAdj0500 (Klonoa)
+------------------------------------
+
+Klonoa (MagDemo08: KLONOA\FILE.IDX+FILE.BIN)
+ FILE.IDX
+ 000h 8 ID "FAdj0500"
+ 008h 38h RAM addresses (80xxxxxxh, 0Ch words)
+ 038h 4 Zero
+ 03Ch 4 RAM address (80xxxxxxh)
+ 040h N*10h File List (including Folder start/end markers)
+ FILE.BIN
+ 000h .. File Data area (split into filesizes from FILE.IDX)
+File List entries:
+ Type 0 (Folder End):
+ 000h 4 Type (0=Folder End)
+ 000h 4 Zero
+ 008h 4 RAM address (always 801EAF8Ch)
+ 00Ch 4 Zero
+ Type 1.a (Folder Start):
+ 000h 4 Type (1=Folder Start)
+ 000h 4 Folder Offset/800h (offset of FIRST file in this Folder)
+ 008h 4 RAM address (always 801EAF8Ch)
+ 00Ch 4 Folder Size/800h (size of ALL files in this Folder)
+ Type 1.b (Force Offset, can occur between Files within a Folder):
+ 000h 4 Type (1=Same as Folder Start)
+ 000h 4 Folder Offset/800h (offset of NEXT file in this Folder)
+ 008h 4 RAM address (always 801EAF8Ch)
+ 00Ch 4 Folder Size/800h (zero for Force Offset)
+ Type 2 (File entries, within Folder Start/End):
+ 000h 4 Type (2=File)
+ 004h 4 Filesize in bytes (4-byte aligned?)
+ 008h 4 RAM address 1 (80xxxxxxh, or zero)
+ 00Ch 4 RAM address 2 (80xxxxxxh)
+File Offsets are usually 4-byte aligned (at offset+filesize from previous
+entry). Except, the first file after Folder Start (and Force Offset) is
+800h-byte aligned.
+The archive contains DOT1 archives, OA05 archives, Ulz compression, and TIM,
+TMD, VAB, SEQ, VB files.
+
+CDROM File Archives in Hidden Sectors
+-------------------------------------
+
+Hidden Sector Overview
+Xenogears, Chrono Cross, and Threads of Fate contain only two files in the ISO
+filesystem (SYSTEM.CNF and the boot executable). The CDROMs contain standard
+ISO data in Sector 10h-16h, followed by Hidden stuff in Sector 17h and up:
+ Sector 10h (00:02:16) Volume Descriptor (CD001) ;\
+ Sector 11h (00:02:17) Volume Terminator (CD001) ;
+ Sector 12h (00:02:18) Path Table 1 ;
+ Sector 13h (00:02:19) Path Table 2 ; standard ISO
+ Sector 14h (00:02:20) Path Table 3 ;
+ Sector 15h (00:02:21) Path Table 4 ;
+ Sector 16h (00:02:22) Root Directory ;/
+ Sector 17h (00:02:23) Hidden ID ;\
+ Sector 18h (00:02:24) Hidden Directory ; hidden directory
+ Sector .. (00:02:xx) Hidden Unknown ;/
+ Sector .. (00:02:xx) Hidden Files... (referenced via Hidden Directory)
+Note: Like normal files, all hidden entries have their last sector flagged as
+SM=89h (that applies to all three Hidden ID, Directory, Unknown entries, and to
+all Hidden Files). For details, see:
+--> CDROM XA Subheader, File, Channel, Interleave
+
+Xenogears (2 discs, 1998)
+ Sector 17h (Hidden.ID)
+ 000h 0Eh ID ("DS01_XENOGEARS"=Disc 1, or "DS02_XENOGEARS"=Disc 2)
+ 00Eh 7F2h Zerofilled
+ Sector 18h..27h
+ 000h N*7 File List entries
+ Sector 28h (Hidden.Unknown)
+ Seems to contain a list of 16bit indices 0000h..1037h,FFFFh in File List
+ (that, as raw list indices, regardless of the directory structure)
+ 000h Unknown 0016 0018 FFFF FFFF 01A8 FFFF FFFF FFFF ;\
+ 010h Unknown FFFF FFFF FFFF FFFF 0A35 0A3A 0D35 0AD3 ; as so on Disc 2
+ 020h Unknown 0A22 0A2E 0A2F FFFF FFFF FFFF FFFF FFFF ; (values<>FFFFh
+ 030h Unknown 0014 0001 0013 FFFF 0075 FFFF FFFF FFFF ; on Disc 1
+ 040h Unknown 0C10 0C14 0C15 0C19 0F52 FFFF FFFF FFFF ; are 5 less, eg.
+ 050h Unknown 0F4C 0B6E 0C4D 1037 0C09 0BAD FFFF FFFF ;
+0011,0013,FFFF..)
+ 060h Unknown 002E 0034 FFFF FFFF FFFF FFFF FFFF FFFF ;
+ 070h Unknown FFFF FFFF FFFF FFFF ;/
+ 078h 2 Disc Number (0001h=Disc 1, 0002h=Disc 2)
+ 07Ah 786h Zerofilled
+ Sector 29h 1st file
+File List entries:
+ 000h 3 24bit Offset (increasing sector number, or 0=special)
+ 003h 4 32bit Size (filesize in bytes, or negative or 0=special)
+The Offset/Size can have following meanings:
+ offset=curr, size=+N file at sector=curr, size N bytes
+ offset=curr, size=-N begin of sub-directory, with N files
+ offset=curr, size=0 empty file, size 0 bytes
+ offset=0, size=0 unused file entry
+ offset=FFFFFFh, size=0 end of root-directory
+Notes: The Hidden.Directory size seems to be hardcoded to 10h sectors
+(alternately, one could treat the sector of the 1st file entry as end of
+Hidden.Directory plus Hidden.Unknown).
+Root entry 0004h and 0005h are aliases for ISO files SYSTEM.CNF and boot EXE.
+There seem to be no nested sub-directories (but there are several DOT1 child
+archives, in root- and sub-directories, eg. 00DCh\0000h\*).
+
+Chrono Cross (2 discs, 1999,2000)
+Threads of Fate (aka Dewprism) (1 disc, 1999,2000)
+ Sector 17h (Hidden.ID)
+ 000h 2 Disc Number (0001h=Disc 1, 0002h=Disc 2)
+ 002h 2 Number of Discs? (0002h) (always 2, even if only 1 disc)
+ 004h 2+2 Sector and Size for Hidden.ID (Sector=0017h, Size=002Ch)
+ 008h 2+2 Sector and Size for Hidden.Directory (Sector=0018h, Size=60E0h)
+ 00Ch 2+2 Sector and Size for Hidden.Unknown (Sector=0025h, Size=0022h)
+ 010h 10h Zerofilled
+ 020h 0Ch Title ID ("CHRONOCROSS",00h) ;Chrono Cross (retail)
+ 09h Title ID ("DEWPRISM",00h) ;Threads of Fate (retail)
+ 10h Title ID ("DEWPRISM_TAIKEN",00h) ;Threads of Fate (demo)
+ 0xxh 7xxh Zerofilled (unused, since Hidden.ID has only Size=2Ch/29h/30h)
+ Sector 18h..24h (Hidden.Directory)
+ 000h N*4 File List entries
+ ... .. Zeropadding (till Size=60E0h, aka 6200 entries)
+ ... 720h Zeropadding (till end of 800h-byte sector)
+ Sector 25h (Hidden.Unknown)
+ Seems to contain a list of 16bit indices 0000h..1791h,FFFFh in File List
+ (though many of the listed indices are unused file list entries)
+ 000h 2 Disc Number (0001h=Disc 1, 0002h=Disc 2)
+ 002h 10h Unknown 0000 1791 1777 1775 00ED 09DF FFFF 0002 ;\same on
+ 012h 10h Unknown 0025 0943 10E3 FFFF FFFF 0C77 0FD9 0FA3 ;/Disc 1+2
+ 022h .. Zerofilled (unused, since Hidden.ID has only Size=0022h)
+ Sector 26h 1st file (same as boot EXE in ISO)
+File List entries:
+ 0-22 Sector number
+ 23 Flag (0=Normal, 1=Unused entry)
+ 24-31 Number of unused bytes in last sector, div8 (0..FFh = 0..7F8h bytes)
+The directory is just a huge list of root files (without any folder structure;
+many of the root files do contain DOT1 child archives though).
+Root entry 0000h and 0001h are aliases for ISO files boot EXE and SYSTEM.CNF.
+Filesizes can be computed as follows (that works for all entries including last
+used entry; which is followed by some unused entries with bit23=1):
+ filesize = ([addr+4]-[addr] AND 7FFFFFh)*800h - ([addr+3] AND FFh)*8
+Unused entries with bit23=1 have Sector pointing to end of previous file
+(needed for filesize calculation). There are some zeropadded entries at end of
+list (with whole 32bit zero). There are hundreds of dummy txt files (24-byte
+"It's CDMAKE Dummy!",0Dh,0Ah,,0Dh,0Ah,20h and File08xxh: 8-byte "dummy",0,0,0)
+although those are real used file entries, each occupying a whole separate
+800h-byte sector.
+
+Threads of Fate (demo version) (MagDemo33: TOF\DEWPRISM.HED+.EXE+.IMG)
+The demo version is using the same directory format as retail version (but with
+Virtual Sector numbers in HED+EXE+IMG files instead of Hidden Sectors).
+ TOF\DEWPRISM.HED (6000h bytes) VirtSector=1Ah, PhysSector=A0A5h
+ TOF\DEWPRISM.EXE (97800h bytes) VirtSector=26h, PhysSector=A0B1h
+ TOF\DEWPRISM.IMG (19EA800h bytes) VirtSector=155h, PhysSector=A1E0h
+The demo's Virtual Sectors start at 1Ah (instead of 17h), to convert them to
+Physical Sectors: Subtract 1Ah, then add starting Sector Number of HED file.
+The HED file contains Hidden.ID, Hidden.Directory, and Hidden.Unknown.
+
+CDROM File Archive HED/DAT/BNS/STR (Ape Escape)
+-----------------------------------------------
+
+Ape Escape KKIIDDZZ.HED/.DAT/.BNS/.STR
+ 000h 52Ch List for .DAT file ;value 0000h..6FFFh = sector 0..6FFFh in DAT
+ 52Ch D4h Zerofilled
+ 600h C4h List for .BNS file ;value 7000h..71AFh = sector 0..1AFh in BNS
+ 6C4h 3Ch Zerofilled
+ 700h 50h List for .STR file(s) ;raw CDROM sector numbers from 00:02:00
+ 750h B0h Zerofilled
+List entries, for all three lists (32bit values):
+ 0-19 File Offset/800h (20bit)
+ 20-31 File Size/800h (12bit)
+The sector numbers in DAT and BNS are basically counted from begin of the .DAT
+file (which has 7000h sectors in retail version, and the .BNS file does follow
+right thereafter on the next sector) (the demo version (MagDemo22: KIDZ\*) has
+only 105Ah sectors in .DAT, and the BNS entries at offset 600h start with 105Ah
+accordingly).
+There are 29 STR files in DEMO\*.STR and STR\*.STR, and 20 of them (?) are
+referenced in HED ? There are also several .ALL files in above folders.
+Note: Most of the STR files in Ape Escape contain polygon animation streams
+rather than BS compressed bitmaps. Ape Escape is (c)1999 by Sony.
+ .HED is 2048 bytes
+ .DAT is 58720256 bytes = 3800000h bytes ;div800h would be 7000h
+ .BNS is 884736 bytes = D8000h bytes ;div800h would be 1B0h
+ .STR's: 7D3Bh+150 = 7DD1h = sector for STR\LAB.STR
+Some files contain RLE compressed TIMs:
+--> CDROM File Compression TIM-RLE4/RLE8
+Some files contain raw headerless SPU-ADPCM (eg. DAT file 00Ah).
+
+CDROM File Archive WAD.WAD, BIG.BIN, JESTERS.PKG (Crash/Herc/Pandemonium)
+-------------------------------------------------------------------------
+
+Below are two slightly different formats. WAD.WAD has unused entries
+00h-filled. The PKG format has them FFh-filled, and does additionally support
+Folders, and does have a trailing ASCII string. There's also a difference on
+whether or not to apply alignment to empty 0-byte files.
+However, the formats can appear almost identical (unused entries, 0-byte files,
+and folders are optional, without them, the only difference would be the
+presence of the ASCII string; which does exist only in 800h-byte aligned PKG's
+though).
+
+WAD.WAD (Crash/Crash)
+Used by Crash Bandicoot 3 (DRAGON\WAD.WAD, plus nested WADs inside of WAD.WAD)
+Used by Crash Team Racing (SPYR02\WAD.WAD, plus nested WADs inside of WAD.WAD)
+Used by Madden NFL'98 (MagDemo02: TIBURON\.DAT except PORTRAIT,SPRITES,XA.DAT)
+Used by N2O (MagDemo09, N2O\PSXMAP.TRM and N2O\PSXSND.SND)
+Used by Speed Racer (MagDemo10: SPDRACER\ALL1.BIN, with 0-byte, unpadded eof)
+Used by Gran Turismo 2 (MagDemo27: GT2\GT2.OVL = 128Kbyte WAD.WAD with GZIP's)
+Used by Jonah Lomu Rugby (LOMUDEMO\SFX\*.VBS, ENGLISH\*.VBS)
+Used by Judge Dredd (*.CAP and *.MAD)
+Used by Spyro 2 Ripto's Rage (SPYRO2\WAD.WAD, and nested WAD's therein)
+Used by Spyro 3 Year of the Dragon (SPYRO3\WAD.WAD, and nested WAD's therein)
+Used by Men: Mutant Academy (MagDemo33: PSXDATA\WAD.WAD\*, childs in PWF)
+ 000h N*8 File List
+ ... .. Zeropadding to 4-byte or 800h-byte boundary (or garbage padding)
+ ... .. File Data...
+The File List can contain Files, and Unused entries:
+ 000h 4 Offset in bytes (4- or 800h-byte aligned, increasing) ;\both zero
+ 004h 4 Size in bytes (always multiples of 800h bytes) ;/when Unused
+The Offset in first entry implies size of the File List (the list has no
+end-marker other than the following zeropadding; which doesn't always exist,
+ie. not in 4-byte aligned files, and not in case of garbage padding).
+The last entry has Offset+Size+Align = Total WAD filesize (except, Speed Racer
+doesn't have alignment padding after the last file).
+The WAD.WAD format doesn't have folder entries, however, it is often used with
+nested WADs inside of the main WAD, which is about same as folders.
+The alignment can be 4-byte or 800h-byte: N2O uses 4-byte for the main WADs.
+Madden NFL '98 uses 800h-byte for main WAD and 4-byte for child WADs (file
+08h,0Ah,0Ch in TIBURON\MODEL01.DAT and file 76h in PIX01.DAT). Crash Bandicoor
+3 and Crash Team Racing use 800h-byte for both main & child WADs (although with
+garbage padding instead of zeropadding in child WAD headers).
+Unused entries have Offset=0, Size=0.
+Empty 0-byte files (should) have Size=0 and Offset=PrevOffs+PrevSize+Align
+(except, Speed Racer has Offset=PrevOffs+PrevSize, ie. without Align for 0-byte
+files).
+
+X-Men: Mutant Academy (MagDemo33,50: PSXDATA\WAD.WAD)
+This does resemble standard WAD.WAD, but with leading 800h-byte extra stuff.
+ 000h 4 ID ("PWF ") ;\
+ 004h 4 Total Filesize (707800h) ;
+ 008h 4 Unknown (1) ; extra stuff
+ 00Ch 4 Number of files (N) ;
+ 010h 7F0h Zerofilled ;/
+ 800h N*8 File List ;\
+ ... .. Zerofilled (padding to 800h-byte boundary) ; standard WAD.WAD
+ ... .. File Data area ;/
+ File List entries:
+ 000h 4 File Offset in bytes (increasing, 800h-byte aligned)
+ 004h 4 File Size in bytes
+The archive contains child archives in DOT1 format, and in standard WAD.WAD
+format (without PWF header).
+
+PKG (Herc/Pandemonium/UnholyWar)
+Used by Pandemonium II (JESTERS.PKG, with Files+Folders+Unused entries)
+Used by Herc's Adventure (BIG.BIN, with Files+Unused entries, without Folders)
+Used by Unholy War (MagDemo12:CERBSAMP.PKG, with 0-byte files and nested PKG's)
+Used by 102 Dalmatians (MagDemo40: PTTR\PSXDEMO.PKG)
+ 000h N*8 File List
+ ... .. ASCII string (junk, but somewhat needed as nonzero end marker)
+ ... .. Zeropadding to 800h-byte boundary; not in 4-byte aligned nested PKG
+ ... .. File Data...
+The File List can contain Files, Folders, and Unused entries. The overall
+format of the list entries is:
+ 000h 4 Offset in bytes (increasing, or 0=First child) ;\both FFFFFFFFh
+ 004h 4 Size in bytes (always nonzero) ;/when Unused
+Files and Folders do have exactly the same format, the only difference is that
+Folders will have Offset=00000000h in the NEXT list entry (in other words, the
+folder entry is followed by child entries, which start with Offset=0).
+Offsets for Root entries are 800h-byte aligned, relative to begin of PKG file.
+Offsets for Child entries are 4-byte aligned, relative to Parent Folder Offset.
+The last Child entry has Offset+Size+Align(4) = Parent Folder Size.
+The last Root entry has Offset+Size+Align(800h) = Total PKG filesize.
+The last Root entry is usually followed by the ASCII string (which looks like
+junk, but it is useful because it equals to NextOffset=Nonzero=NoChilds).
+ Example
+ 00003800h,00000666h ;root00h (file 666h bytes, padded=800h)
+ 00004000h,00000300h ;root01h\.. (folder 300h bytes, padded=800h)
+ 00000000h,000000FDh ;root01h\child00h (file FDh bytes, padded=100h) ;\300h
+ FFFFFFFFh,FFFFFFFFh ;root01h\child01h (unused) ; byte
+ 00000100h,000001FDh ;root01h\child02h (file 1FDh bytes, padded=200h) ;/
+ 00004800h,00001234h ;root02h (file 1234h bytes, padded=1800h)
+ 00006000h,00001234h ;root03h (file 1234h bytes, padded=1800h)
+ FFFFFFFFh,FFFFFFFFh ;root04h (unused)
+ 00007800h,00001234h ;root05h (file 1234h bytes, padded=1800h)
+ etc.
+Notes: Unused entries can occur in both root and child folders (except, of
+course, not as first or last entry in child folders). Folders seem to occur
+only in root folder (although the format would allow nested folders).
+Alternately, instead of Folders, one can use nested PKG's (the nested ones are
+using 4-byte align, without ASCII string and zeropadding in header).
+
+CDROM File Archive BIGFILE.BIG (Gex)
+------------------------------------
+
+Gex (GXDATA\BIGFILE.BIG and nested BIG files therein)
+ 000h 4 Number of Files (eg. F4h)
+ 004h 0Ch Zero
+ 010h N*10h File entries
+ ... 4 Archive ID (eg. 00000000h, FF53EC8Bh, or 83FFFFFFh)
+ ... .. Zeropadding to 800h byte boundary
+ ... .. File Data
+File Entries:
+ 000h 4 Archive ID (same value as in above header)
+ 004h 4 Filename checksum or so (randomly ordered, not increasing)
+ 008h 4 Filesize in bytes
+ 00Ch 4 Fileoffset (800h-byte aligned) (increasing)
+Filetypes in the archive include...
+ looks like a lot of raw data without meaningful file headers...
+ file C3h,ECh are raw SPU-ADPCM
+ file 08h,09h are nested BIG archives, but with FileEntry[00h]=FF53EC8Bh
+ file D9h,DAh are nested BIG archives, but with FileEntry[00h]=83FFFFFFh
+FileEntry[04h] sometimes has similar continous values (maybe caused by similar
+filenames, and using a simple checksum, not CRC32).
+
+CDROM File Archive BIGFILE.DAT (Gex - Enter the Gecko)
+------------------------------------------------------
+
+Gex - Enter the Gecko - BIGFILE.DAT
+Used by Gex 2: Enter the Gecko (BIGFILE.DAT)
+Used by Gex 3: Deep Cover Gecko (MagDemo20: G3\BIGFILE.DAT) -- UNSORTED
+Used by Akuji (MagDemo18: AKUJI\BIGFILE.DAT)
+Used by Walt Disney World Racing Tour (MagDemo35: GK\BIGFILE.DAT) -- UNSORTED
+ 000h 4 Number of Files (C0h)
+ 004h N*18h File entries
+ ... .. Zeropadding to 800h byte boundary
+ ... .. File Data
+File Entries:
+ 000h 4 Random
+ 004h 4 Filesize in bytes (uncompressed size)
+ 008h 4 Filesize in bytes (compressed size, or 0=uncompressed)
+ 00Ch 4 Fileoffset (800h-byte aligned) (increasing, unless UNSORTED)
+ 010h 4 Random
+ 014h 4 Random (or ascii in 1st file)
+LZ Decompression:
+ @@collect_more:
+ flagbits=[src]+[src+1]*100h+10000h, src=src+2 ;16bit flags, unaligned
+ @@decompress_lop:
+ if dst>=dst.end then goto @@decompress_done
+ flagbits=flagbits SHR 1
+ if zero then goto @@collect_more
+ if carry=0 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ len=([src] AND 0Fh)+1), disp=([src] AND 0F0h)*10h+[src+1], src=src+2
+ if len=1 or disp=0 then goto invalid ;weirdly, these are left unused
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+Filetypes in the archive include...
+ standard TIM (eg. file 01h,02h)
+ malformed TIM (eg. file 0Fh,14h) (with [8]=2*cx*cy+4 instead 2*cx*cy+0Ch)
+ crippled VAB (eg. file 0Eh,13h) (with hdr=filesize-4 plus raw ADPCM samples)
+ several DNSa (eg. file 0Dh,12h,17h,BCh) SND sound? (also used by kain)
+ PMSa (eg. Gex 3, World Racing) (SMP spu-adpcm samples)
+ there seem to be no nested DAT files inside of the main DAT file
+Note: same malformed TIMs are also in Legacy of Kain (folder0004h\file0013h).
+
+CDROM File Archive FF9 DB (Final Fantasy IX)
+--------------------------------------------
+
+DB Archive
+ 000h 1 ID (DBh)
+ 001h 1 Number of Types
+ 002h 2 Zero (0)
+ 004h N*4 Type List
+ ... .. File Lists & File Data for each Type
+Type List entries:
+ 000h 3 Offset to File List (self-relative, from current entry in Type List)
+ 003h 1 Data Type (00h..1Fh)
+File List:
+ 000h 1 Data type (00h..1Fh) (same as in Type List)
+ 001h 1 Number of Files
+ 002h 2 Zero (0)
+ 004h N*2 File ID List (unique ID per type) (different types may have same ID)
+ ... .. Zeropadding to 4-byte boundary
+ ... N*4 Offset List (self-relative, from current entry in Offset List)
+ ... 4 End Offset (first-relative, from first entry in Offset List)
+ ... .. File Data (referenced from above Offset List)
+
+Data Types
+ 00h Misc (DOT1 Archives, or other files)
+ 01h Unused?
+ 02h Reportedly 3D Model data (vertices,quads,triangles,texcoords)
+ 03h Reportedly 3D Animation sequences
+ 04h TIM Texture
+ 05h Reportedly Scripts (hdr="EV") (eg. dir04\file32\1B-0001)
+ 06h ? (eg. dir02\file*)
+ 07h Sound "Sequencer Data" (hdr="AKAO") (eg. dir09\file*)
+ 08h Sound? tiny files (hdr="AKAO") (eg. dir04\file32\1B-0001)
+ 09h Sound Samples (hdr="AKAO") (eg. dir0B\file*)
+ 0Ah Reportedly Field Tiles and Field Camera parameters
+ 0Bh Reportedly Field Walkmesh (eg. dir04\file32\1B-0001)
+ 0Ch Reportedly Battle Scene geometry (eg. dir06\file*)
+ 0Dh ? (eg. dir01\file01)
+ 0Eh Unused?
+ 0Fh Unused?
+ 10h ? (eg. dir05\file*)
+ 11h ? (eg. dir05\file*)
+ 12h Reportedly CLUT and TPage info for models (eg. dir04\file32\1B-0001)
+ 13h Unused?
+ 14h ? (eg. dir05\file*)
+ 15h Unused?
+ 16h ? (eg. dir04\file32\1B-0001)
+ 17h ? (eg. dir04\file32\1B-0000)
+ 18h Sound (hdr="AKAO") (eg. dir04\file32\1B-0001)
+ 19h ? (eg. dir04\file32\1B-0001)
+ 1Ah ? (eg. dir06\file*)
+ 1Bh DB Archives (ie. further DB's nested inside of the parent DB archive)
+ 1Ch ? (eg. dir04\file32\1B-0001)
+ 1Dh ? (eg. dir03\file2328\1B-0001)
+ 1Eh ? (eg. dir04\file32\1B-0001)
+ 1Fh ? (eg. dir04\file32\1B-0001)
+ 20h..FFh Unused?
+
+CDROM File Archive Ace Combat 2 and 3
+-------------------------------------
+
+Ace Combat 2 (Namco 1997) (ACE2.DAT and ACE2.STH/STP)
+There are two archives, stored in three files:
+ ACE2.DAT Directory for Data in ACE2.DAT itself ;normal binary data
+ ACE2.STH Directory for Data in separate ACE2.STP file ;streaming data
+Directory Format:
+ 000h 4 Unknown (1)
+ 004h 4 Number of entries (N)
+ 008h N*8 File List
+File List entries (64bit):
+ 0-27 28bit Size/N (DAT=Size/4, STP=Size/800h)
+ 28-31 4bit Type or Channel Number (see below)
+ 32-63 32bit Offset/800h in ACE2.STP or ACE2.DAT file
+The files are interleaved depending on the Type/Channel number:
+ File Bit28-31 Channel Sector types... Interleave Notes
+ DAT 0 ch=0 DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD 1:1 data (normal)
+ DAT 2 ch=0 DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD 1:1 data (exe)
+ STH 0-6 ch=0-6 S.......S.......S.......S....... 1:8 stereo
+ STH 8 ch=1 vvvvvvvSvvvvvvvSvvvvvvvSvvvvvvvS 1:1 video+stereo
+ Whereas D=data, S=Stereo/Audio, v=video, .=other channels
+Note: The DAT file does additionally contain PreSizeDOT1 and DOT1 child
+archives.
+Demo: The archives in demo version (MagDemo01: ACE2.*) contain only a handful
+of files; the two EXE files in demo DAT archive are only 800h-byte dummy files,
+and demo STP is corrupted: Recorded as CDROM image with 920h-byte sectors,
+instead of as actual CD-XA sectors).
+
+Ace Combat 3 Electrosphere (Namco 1999) (ACE.BPH/BPB and ACE.SPH/SPB)
+There are two archives, stored in four files:
+ ACE.BPH Directory for Data in separate ACE.BPB file ;normal binary data
+ ACE.SPH Directory for Data in separate ACE.SPB file ;streaming data
+Directory Format:
+ 000h 4 ID "AC3E" (=Ace Combat 3 Electrosphere)
+ 004h 4 Type (BPH=3=Data?, SPH=1=Streaming?)
+ 008h 2 BCD Month/Day? (Japan=0427h, US=1130h)
+ 00Ah 2 BCD Year (or zero) (SPH=1999h, BPH=0)
+ 00Ch 4 Unknown (SPH=0, BPH/US=16CFh or BPH/JP=1484h)
+ 010h 4 Number of entries (N)
+ 014h N*8 File List
+File List entries (64bit), when Bit31=1 (normal entries):
+ 0-18 19bit Size/N (BPH=Size/4, SPB=Size/800h)
+ 19-23 5bit Channel Number (BPH=0, SPH=0..1Fh)
+ 24-26 3bit Channel Interval (BPH=0, SPH=1 SHL N, eg. 3=Interval 1:8)
+ 27 1bit Video Flag (0=No, 1=Has Video sectors)
+ 28 1bit Audio Flag (0=No, 1=Has Audio sectors)
+ 29 1bit Always 1 (except special entries with Bit31=0, see below)
+ 30 1bit Unknown (US: Always 1, Japan: 0 or 1)
+ 31 1bit Always 1 (except special entries with Bit31=0, see below)
+ 32-63 32bit Offset/800h in ACE.BPB or ACE.SPB file (or 0 when bit31=0 ?)
+File List entries (64bit), when Bit31=0:
+ For unknown purpose, the normal entries with Bit31=1 are occassionally
+followed by one or more entries with Bit31=0.
+ Unknown if those entries do affect the actual storage (like switching to
+ different channel numbers, or jumping to non-continous sector numbers).
+ That unknown stuff exists in Japanese version only, not in US version.
+ 0-18 19bit Unknown (maybe some snippet size value in whatever units?)
+ 19-23 5bit Always 0 (instead of Channel)
+ 24-27 4bit Same as in most recent entry with Bit31=1
+ 28-31 4bit Always 5 (instead of Flags)
+ 32-63 32bit Always 0 (instead of Offset)
+The files are interleaved depending on the Channel Interval setting (and with
+types data/audio/video depending on Flags).
+ File Bit24-31 Sector types... Interval Content
+ BPH.US E0h DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD 1:1 data
+ SPH.US F8h SvvvvvvvSvvvvvvvSvvvvvvvSvvvvvvv 1:1 stereo+video
+ SPH.US FBh S.......v.......S.......v....... 1:8 stereo+video
+ SPH.US F3h S.......S.......S.......S....... 1:8 stereo
+ SPH.US F4h S...............S............... 1:16 stereo
+ SPH.US F5h M............................... 1:32 mono
+ BPH.JAP E0h DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD 1:1 data
+ SPH.JAP B8h,F8h SvvvvvvvSvvvvvvvSvvvvvvvSvvvvvvv 1:1 stereo+video
+ SPH.JAP B9h Svvv....vvvv....Svvv....vvvv.... 1:2 stereo+video
+ SPH.JAP BAh,FAh Mv......vv......vv......vv...... 1:4 (4:8) mono+video
+ SPH.JAP BBh,FBh S.......v.......S.......v....... 1:8 (2:8) stereo+video
+ SPH.JAP B3h,F3h S.......S.......S.......S....... 1:8 stereo
+ SPH.JAP B5h,F5h M............................... 1:32 mono
+ Whereas D=data, S=Stereo/Audio, M=Mono/Audio, v=Video, .=Other channels
+As shown above, interval 1:2 and 1:4 are grouped as 4:8 and 2:8 (ie. 4 or 2
+continous sectors per 8 sectors).
+The Subheader's Channel number is specified in the above directory entries,
+Subheader's File number is fixed (0 for BPB, and 1 for SPB).
+--> CDROM XA Subheader, File, Channel, Interleave
+The SPB file is about 520Mbyte in both US and Japan, however, the Japanese
+version does reportedly contain more movies and some storyline that is missing
+in US/EU versions.
+The BPB file contains DOT1 child archives, and Ulz compressed files.
+--> CDROM File Compression Ulz/ULZ (Namco)
+The SPB file contains movies with non-standard STR headers (and also uncommon:
+interleaved videos on different channels, at least so in the japanese version).
+Demo: The archives do also exist on the demo version (MagDemo30: AC3\*), but
+the .SPB file is corrupted: Recorded as a RIFF/CDXAfmt file, instead of as
+actual CD-XA sectors).
+
+CDROM File Archive NSD/NSF (Crash Bandicoot 1-3)
+------------------------------------------------
+
+NSD/NSF versions
+ v0 Crash Bandicoot Prototype (oldest known prototype from 08 Apr 1996)
+ v1 Crash Bandicoot 1 (retail: S*\*.NSD and .NSF)
+ v2 Crash Bandicoot 2 (MagDemo02: CRASH\S0\*.NSD and .NSF)
+ v3 Crash Bandicoot 3 Warped (MagDemo26,50: (S0\*.NSD and .NSF)
+
+ ____________________________________ NSD _____________________________________
+
+Overall NSD Structure (v0 contains only the Lookup entries)
+ 0000h 100h*4 Lookup Table, using index=((Filename/8000h) AND FFh) ;\
+ 0400h 4 Number of Chunks in .NSF file ; Lookup
+ 0404h 4 Number of Files in Lookup File List (N) ;/
+ 0408h 4 Level Data Filename (eg. 4F26E8DFh="DATh.L") ;-LevelDat
+ 040Ch 4 Bitmap Number of Colors (100h) (P) (0=None) ;\
+ 0410h 4 Bitmap Width (200h or 1B0h) (X) (0=None) ; Bitmap
+ 0414h 4 Bitmap Height (0D8h or 090h) (Y) (0=None) ;/
+ 0418h 4 Compression: Offset/800h of first uncompressed chunk ;\
+ 041Ch 4 Compression: Number of compressed chunks (0..40h) ; Compress
+ 0420h 40h*4 Compression: Compressed Chunk List (0=unused entry) ;/
+ ... N*8 Lookup File List ;-Lookup
+ ... .. Level Data (size/format varies, see below) ;-LevelDat
+ ... P*2 Bitmap Palette (16bit values, 8000h..FFFFh) ;\Bitmap
+ ... X*Y Bitmap Pixels (0D8h*200h) ;/
+There are four .NSD versions, which can be distinguished via filesize:
+ v0 NSD Filesize=408h + N*8 ;-Lookup only
+ v1 NSD Filesize=520h + N*8 + P*2+X*Y + 210h ;\
+ v2 NSD Filesize=520h + N*8 + P*2+X*Y + 1DCh+S*18h ; with extra stuff
+ v3 NSD Filesize=520h + N*8 + P*2+X*Y + 2DCh+S*18h ;/
+Note: v0 is mainly used by the Crash Bandicoot prototype, but the Crash
+Bandicoot 1 retail version does also have a few v0 files.
+
+NSD Lookup
+The lookup table allows to find files (by filenames) in the NSF files. It does
+merely contain the NSF chunk number, so one must load/decompress that chunk to
+find the file's exact size/location in that chunk.
+One can create a complete file list by scanning the whole NSF file without
+using the NDS lookup table.
+ Lookup File List entries (indexed via Lookup Table):
+ 00h 4 Chunk Number in .NSF file
+ 04h 4 Filename (five 6bit characters)
+Filenames:
+ 0 Type (always 1=Filename) (as opposed to 0=Memory Pointer)
+ 1-6 5th character ;-Extension ;\character set is:
+ 7-12 4th character ;\ ; 00h..09h="0..9"
+ 13-18 3rd character ; Name ; 0Ah..23h="a..z"
+ 19-24 2nd character ; ; 24h..3Dh="A..Z"
+ 25-30 1st character ;/ ;/3Eh..3Fh="_" and "!"
+ 31 Always zero?
+Special name: 6396347Fh="NONE.!"
+
+NSD Level Data
+Level Data exists in NSD v1-v3 (v0 does also have Level Data, but it's stored
+in NSF file "DAT*.L" instead of in the NSD file). There are two major versions:
+ Level Data in NSD v1 (or NSF v0 file DAT*.L):
+ 000h 4 01h ;\
+ 004h 4 Level Number (xxh) (same as xx in S00000xx.NSD/NSF) ;
+ 008h 4 3807C8FBh = "s0_h.Z" ? ; LevelDat
+ 00Ch 4 Zero ; v1
+ 010h 4 Zero ;
+ 014h L*4 Namelist (40h*4) ;
+ ... 4 5Ah ;
+ ... F8h Zerofilled ;/
+ Level Data in NSD v2-v3:
+ 000h 4 Number of Spawn Points (S) ;\
+ 004h 4 Zero ;
+ 008h 4 Level Number (xxh) (same as xx in S00000xx.NSD/NSF) ; LevelDat
+ 00Ch 4 Number of Objects? (can be bigger than below list) ; v2/v3
+ (eg. 1BDh or A5h or E4h) ;
+ 010h L*4 Namelist for Objects? (v2=40h*4, or v3=80h*4) ;
+ ... 4 Unknown, always 5Ah (maybe just list end marker?) ;
+ ... C8h Zerofilled ;
+ ... S*18h Spawn Points ;/
+
+NSD Bitmap
+This bitmap is displayed while loading the level.
+
+NSD Compression Info
+Compression is only used in v1 (v2-v3 do also have the compression entries at
+[418h..51Fh], but they are always zerofilled).
+ Compressed Chunk List entries at [420h..51Fh]:
+ 0-5 Compressed Chunk Size/800h (1..1Fh=800h..F800h bytes, 20h..3Fh=Bad?)
+ 6-31 Compressed Chunk Offset/800h
+Note: Crash Bandicoot 1 retail does also have a few uncompressed files (either
+v0 files without compression info, or v1 files with zerofilled compression
+info).
+
+ ____________________________________ NSF _____________________________________
+
+NSF files consist of 64Kbyte chunks (compressed chunks are smaller, but will be
+64Kbyte after decompression). Each chunk can contain one or more file(s). That
+implies that all files must be smaller than 64Kbyte (larger textures or ADPCM
+samples must be broken into multiple smaller files).
+All files (except Textures) are NSF Child Archives which contain one or more
+smaller files/items.
+
+NSF Chunk Types
+ N*8Kbyte-Compressed-chunks:
+ 000h 2 ID, always 1235h (instead of 1234h)
+ 002h 2 Zero
+ 004h 4 Decompressed Size (max 10000h) (usually 9xxxh..Fxxxh, often Fxxxh)
+ 008h 4 Skip Size (max 40h or so, when last LZSS_len was 40h)
+ 00Ch .. Compressed data
+ ... SK Unused (Skip size)
+ ... .. Final uncompressed bytes (10000h-compressed_size-skip_size)
+ 64Kbyte-Texture-chunks:
+ 000h 2 ID, always 1234h
+ 002h 2 Chunk Family (1=Texture)
+ 004h 4 Filename (five 6bit characters)
+ 008h 4 File Type (5=Texture)
+ 00Ch 4 Checksum (sum of bytes ar [0..FFFFh], with initial [0Ch]=00000000h)
+ 010h ... Zerofilled
+ 020h ... Texture data (raw VRAM data, FFE0h bytes?)
+ 64Kbyte-NonTexture-chunks:
+ 000h 2 ID, always 1234h
+ 002h 2 Chunk Family (0=Misc or 2..5=Sound)
+ 004h 4 Chunk Number*2+1
+ 008h 4 Number of Files (N) (can be 0, eg. prototype S0000003 chunk21h)
+ 00Ch 4 Checksum (sum of bytes ar [0..FFFFh], with initial [0Ch]=00000000h)
+ 010h N*4 File List (Offsets from ID=1234h to entries) (4-byte aligned)
+ ... .. Offset for end of last File
+ ... .. File Data (NSF Child Archives) (includes Type/Filename)
+ ... .. Padding to 10000h-byte boundary
+
+NSF Child Archives
+ 000h 4 ID, always 0100FFFFh
+ 004h 4 Filename (five 6bit characters)
+ 008h 4 File Type (01h..04h, or 06h..15h)
+ 00Ch 4 Item Count (I)
+ 010h I*4 Item List (Offsets from ID=0100FFFFh to items) (...unaligned?)
+ ... .. Offset for end last item
+ ... .. Data (Items)
+
+NSF Chunk Loading and Decompression
+The compression is a mixup of LZSS and RLE. Compressed chunks are max F800h
+bytes tall (10000h bytes after decompression).
+ dst=chunk_buffer_64kbyte
+ if chunksize is known (from NSD file)
+ src=dest=dst+10000h-chunksize
+ diskread(fpos,src,chunksize)
+ else (when parsing raw NSF file without NSD file)
+ src=temp_buffer_64kbyte
+ diskread(fpos,src,10000h)
+ dst_start=dst, src_start=src
+ if halfword[src+00h]<>1234h then ;check ID (1234h=raw, or 1235h=compressed)
+ dst_end=dst+word[src+04h]
+ skip_size=word[src+08h]
+ src=src+0Ch
+ while dst<dst_end
+ x=[src], src=src+1
+ if x<80h then
+ for i=0 to x-1, [dst]=[src], dst=dst+1, src=src+1, next i ;uncompressed
+ else
+ x=(x AND 7Fh)*100h+[src], src=src+1
+ disp=x/8, len=(x AND 7)+3, if len=0Ah then len=40h
+ for i=0 to len-1, [dst]=[dst-disp], dst=dst+1, next i ;compressed
+ src=src+src_skip
+ if src<>dst then
+ while dst<dst_start+10000h, [dst]=[src], dst=dst+1, src=src+1 ;uncompressed
+ chunksize=src-src_start ;<-- compute (when chunksize was unknown)
+ fpos=fpos+chunksize ;<-- fileposition of next chunk
+As shown above, the chunk is intended to be loaded to the end of the
+decompression buffer, so trailing uncompressed bytes would be already in place
+without needing further relocation (despite of that intention, the actual game
+code is uselessly relocating src to dst, even when src=dst).
+Note: All compressed files seem to have an uncompressed copy with same filename
+in another chunk (the NSD Lookup table does probably(?) point to the compressed
+variant, which should reduce CDROM loading time).
+
+ _________________________________ Filetypes __________________________________
+
+Filetype Summary
+Below shows File Type, Chunk Family, Extension (5th character of filename), the
+version where the type is used, 4-letter type names (as found in the EXE
+files), and a more verbose description.
+ Typ Family Ext Ver Name Description
+ 00h - ! - NONE Nothing
+ 01h 0 V all SVTX Misc.Vertices
+ 02h 0 G all TGEO Misc.Model ;\changed format in v2-v3 ?
+ 03h 0 W all WGEO Misc.WorldScenery ;/
+ 04h 0 S all SLST Misc.UnknownSLST
+ 05h 01h T all TPAG Texture.VRAM
+ 06h 0 L v0 LDAT Misc.LevelData ;-stored in NSD in v1-v3
+ 07h 0 Z all ZDAT Misc.Entity ;-changed format in v2-v3 ?
+ 08h - - - CPAT Internal?
+ 09h - - - BINF Internal?
+ 0Ah - - - OPAT Internal?
+ 0Bh 0 C all GOOL Misc.GoolBytecode
+ 0Ch 02h A v0 ADIO OldSound.Adpcm ;\type 0Ch
+ 0Ch 03h A all ADIO Sound.Adpcm ;/
+ 0Dh 0 M all MIDI Misc.MidiMusic ;-changed format in v1-v3 ?
+ 0Eh 04h N all INST Sound.Instruments
+ 0Fh 0 D v0-1 IMAG Misc.UnknownIMAG ;\type 0Fh
+ 0Fh 0 X v2-3 VCOL Misc.UnknownVCOL ;/
+ 10h - - - LINK Internal?
+ 11h 0 P v0-1 MDAT Misc.UnknownMDAT ;\type 11h
+ 11h 0 R v3 RAWD Misc.UnknownRAWD ;/
+ 12h 0 U v0-1 IPAL Misc.Unknown ;-Crash 1 only? (eg. S0000019.NSF)
+ 13h 0 B v1-3 PBAK Misc.DemoPlayback ;-eg. in MagDemo02
+ 14h 0 V v0-1 CVTX Misc.UnknownCVTX ;\type 14h
+ 14h 05h O v2-3 SDIO Speech.Adpcm ;/
+ 15h 0 D v2-3 VIDO Misc.UnknownVIDO
+As shown above, Type 0Ch is used with family 02h/03h, and Type 0Fh,11h,14h have
+two variants each (with different extensions). The Extensions do usually
+correspong with the Types (although extension V,D are used for two different
+types each).
+
+See also:
+https://gist.github.com/ughman/3170834
+https://dl.dropbox.com/s/fu29g6xn97sa4pl/crash2fileformat.html
+
+Weird Note
+"Sound entries don't need to be aligned as strictly for most (all?) emulators."
+What does that mean???
+Is there a yet unknown 16-byte DMA alignment requirement on real hardware?
+
+CDROM File Archive STAGE.DIR and *.DAT (Metal Gear Solid)
+---------------------------------------------------------
+
+Metal Gear Solid (MagDemo13: MGS\*)
+Metal Gear Solid (MagDemo25: MGS\*)
+Metal Gear Solid (MagDemo44: MGS\*) (looks same as in MagDemo13)
+Metal Gear Solid (Retail: MGS\*)
+
+Summary of ISO files in MGS folder (with filesizes for different releases)
+ File MagDemo13/44 MagDemo25 Retail/PAL
+ .EXE 9C000h 9C800h 9D800h ;-executable
+ STAGE.DIR 590800h 11A7800h 42AE000h ;-main archive
+ FACE.DAT 2CA000h 3Dh (txt) 358800h ;-face animation archive
+ ZMOVIE.STR - - 2D4E800h ;-movie archive
+ DEMO.DAT 149B000h 3Dh (txt) EC20000h ;\DAT/SYM combos (the .SYM
+ DEMO.SYM 88h - - ; files were leaked in
+ VOX.DAT 14F2000h 9F800h B054800h ; MagDemo13/MagDemo44 only)
+ VOX.SYM 988h - - ;/
+ BRF.DAT - 66800h 575800h ;\whatever, unknown format(s)
+ RADIO.DAT 16CB8h 3Dh (txt) 1AA956h ;/
+
+STAGE.DIR:
+ 000h 4 Size of File List (N*0Ch)
+ 004h N*0Ch Folder List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. Folder Data
+ Folder List entries:
+ 000h 8 Foldername (zeropadded if less than 8 chars) ;nickname=stg
+ 008h 4 Offset/800h to File List
+ Folder Data (per folder):
+ 000h 2 Unknown (always 1) (maybe File List size/800h?)
+ 002h 2 Folder Size/800h (of whole folder, with file list plus file data)
+ 004h N*8 File List
+ ... Zeropadding to 800h-byte
+ 800h Data (for files in current folder)
+ File List entries:
+ 000h 2 File ID (checksum on name)
+ 002h 1 File Family (one of following chars: "cnrs")
+ 003h 1 File Type (one of following chars: "abcdeghiklmoprswz",FFh)
+ 004h 4 File Size (or File Offset, when File Family="c")
+Combinations of Family/Type characters are:
+ .?a ???? if any ???? (does NOT exist on PAL disc 1) ;nickname=azm
+ .sb MIPS binary code (leading) ;nickname=bin
+ .cc Whatever (eg. vr10\*, s01a\*) ;nickname=con
+ .nd Texture Archive (leading) (contains PCX files) ;nickname=dar
+ .rd Misc Archive (leading) (eg. init\*) ;nickname=dar
+ .se Sound Effects? (trailing) ;nickname=efx
+ .cg Whatever, reportedly bytecode functions ;nickname=gcx
+ .ch Whatever ;nickname=hzm
+ .ci Whatever (eg. ending\*, s01a\*) ;nickname=img
+ .ck Whatever, model? aka "pat_xxx" files ;nickname=kmd
+ .cl Lights, first word = size/10h ;nickname=lit
+ .sm Sound Music? Nested DOT1+DOTLESS Archives ;nickname=mt3
+ .co Whatever "OARa" (eg. d16e\*, s00a\*, s02c\*) ;nickname=oar
+ .cp PCX bitmap (eg. init\*) ;nickname=pcc
+ .cr Whatever "sNRJ1F" (eg. roll\*) ;nickname=rar
+ .cs Whatever (eg. d16e\*, s01a\*) ;nickname=sgt
+ .sw Wave Archive (trailing) ;nickname=wvx
+ .cz Whatever "KMDa" (eg. s11a, a11c, s14e, s15a) ;nickname=zmd
+ .c,FFh End of Family="c" area ;nickname=dar?
+Files are starting on 800h-byte boundaries. Files with Family="c" are special,
+they contain an Offset entries instead of a Size entries, that Offsets are
+4-byte aligned (relative to the 800h-byte aligned offset of the first
+Family="c" entry), the list of Family="c" entries is terminated by an entry
+with Family="c" and Type=FFh (which contains the end-offset of the last
+c-Family entry, aka the size of all c-Family entries).
+Note: The above 3-letter nicknames are used on some webpages (unknown why,
+maybe they are derived from MGS filename extensions in the PC version).
+
+FACE.DAT (face animations for video calls):
+This contains several large blocks (supposedly one per stage, each block having
+its own file list). There is no directory to find the begin of the separate
+blocks, but one can slowly crawl through the file:
+ NextBlock = CurrBlock + 4 + Offset(lastfile)+Size(lastfile) + Align800h
+The content of each block is:
+ 000h 4 Number of Files in this block (eg. 19h or 1Ch)
+ 004h N*0Ch File List for this block
+ ... .. File Data for this block
+ ... .. Zeropadding to 800h-byte boundary (followed by next block, if any)
+ File List entries:
+ 000h 2 File Type (0=Main/Eye/Mouth frames, 1=All frames are full size)
+ 002h 2 File ID (name checksum?)
+ 004h 4 Filesize in bytes
+ 008h 4 Offset in bytes, minus 4
+Type 0 Files in FACE.DAT:
+ This type use a single palette for all frames, and only the first frame is
+ full 52x89pix, the other frames contain only the update sections (eg. eyes).
+ 000h 4 Offset to 200h-byte palette (usually 20h) ;\Main
+ 004h 4 Offset to Main Bitmap (52x89pix) (usually 220h) ;/
+ 008h 4 Offset to 4th Bitmap (usually xxxxh or 0=None) ;\Eyes
+ 00Ch 4 Offset to 5th Bitmap (usually xxxxh or 0=None) ;/
+ 010h 4 Zero
+ 014h 4 Offset to 2nd Bitmap (usually 143Ch or 0=None) ;\Mouth
+ 018h 4 Offset to 3rd Bitmap (usually xxxxh or 0=None) ;/
+ 01Ch 4 Zero
+ 020h 200h Palette (256 colors) ;\Main
+ 220h 1218h Main Bitmap ;/
+ 1438h 4 Zero
+ 143Ch .. 2nd Bitmap (if any) ;\Mouth
+ ... .. 3rd Bitmap (if any) ;/
+ ... .. 4th Bitmap (if any) ;\Eyes
+ ... .. 5th Bitmap (if any) ;/
+Type 1 Files in FACE.DAT:
+ This type use separate palettes for each frame, all frames are full 52x89pix.
+ 000h 4 Number of frames
+ 004h N*0Ch Frame List
+ ... 200h 1st Frame Palette
+ ... 1218h 1st Frame Bitmap (52x89pix)
+ ... 4 ?
+ ... 200h 2nd Frame Palette
+ ... 1218h 2nd Frame Bitmap (52x89pix)
+ ... 4 ?
+ ... .. 3rd Frame ...
+ Frame List entries:
+ 000h 4 Offset to Palette
+ 004h 4 Offset to Bitmap (usually at Palette+200h)
+ 008h 4 Unknown (often 000x000xh)
+Bitmap Format (for both Type 0 and Type 1):
+ 000h 1 Offset X (always 00h in Main Bitmap)
+ 001h 1 Offset Y (always 00h in Main Bitmap)
+ 002h 1 Width (always 34h in Main Bitmap, or less in 2nd-5th bitmap)
+ 003h 1 Height (always 59h in Main Bitmap, or less in 2nd-5th bitmap)
+ 004h .. Bitmap Pixels at 8bpp (Width*Height bytes)
+
+DEMO.DAT, DEMO.SYM
+VOX.DAT, VOX.SYM
+The .DAT files contain several huge blocks, found on 800h-boundaries starting
+with:
+ 10 08 00 00 0x 00 00 00 ..
+The .SYM files (if present) contain Names and .DAT Offsets/800h for those huge
+blocks in text format:
+ "0xNNNNNNNN name",0Ah
+VOX.DAT does (among others) contain SPU-ADPCM chunks with 2004h bytes or less,
+that is, a 1+3 byte chunk header (01h=SPU-ADPCM, 002004h=Size), plus 2000h byte
+or less SPU-ADPCM data.
+
+RADIO.DAT:
+Whatever, contains chunks with text messages, chunks are about as so:
+ 000h 4 Unknown (eg. 36h,BFh,5Eh,00h)
+ 004h 4 Unknown (eg. 03h,13h,00h,00h)
+ 008h 1 Unknown (eg. 80h)
+ 009h 2 Chunk Size (eg. 0xh,xxh) ;big-endian
+ .. .. Chunk Data (Chunk Size-2 bytes) (binary stuff, and text strings)
+
+BRF.DAT:
+Contains several "folders" in this format:
+ 000h 4 Number of files in this folder
+ 004h .. File(s)
+ ... .. 01h-padding to 800h-byte boundary
+ Files have this format:
+ 000h .. Filename ("name.pll",00h)
+ ... .. Zeropadding to 4-byte boundary (aligned to begin of BRF.DAT)
+ ... 4 File data size (usually a multiple of 4)
+ ... .. File data
+ ... 1 Zero (00h)
+The above "folders" are then followed by several PCX files:
+ 000h .. PCX file (starting with 0A,05,01,01 or 0A,05,01,08)
+ ... .. 01h-padding to 800h-byte boundary
+The first part with .pll files does contain some kind of chunk sizes that could
+be used to find the next entry (but that would be very slow).
+The second part with .PCX files doesn't have any chunk sizes at all (though one
+could decompress the .PCX file to find the end of each file) (also one could
+guess/find them by looking for 0A,05,01,01/08 on 800h-byte boundaries).
+
+ZMOVIE.STR (movie archive with several STR files with subtitles)
+--> CDROM File Video Streaming STR Variants
+
+STAGE.DIR\*\*.sb - stage binary/header
+This is the first file in most folders (except "init*" folders).
+The file contains MIPS binary program code. And, there are ascii strings near
+end of .sb files, which include filenames, alike:
+ "name.c",00h + garbage-padding to 4-byte boundary ;<-- maybe source code?
+ "pat_lamp",00h + zero- padding to 4-byte boundary ;<-- name for File ID !
+Those filenames do cover some (not all) of the name checksums in the STAGE.DIR
+folder.
+
+STAGE.DIR\*\*.cp, STAGE.DIR\*\*.nd\.p, BRF.DAT\* - PCX bitmap files
+MGS is using customized/corrupted PCX files as standard texture format (in
+STAGE.DIR\*\*.cp, STAGE.DIR\*\*.nd\*.p, and BRF.DAT\*).
+For details on PCX format (and MGS-specific customizations), see:
+--> CDROM File Video Texture/Bitmap (PCX)
+Apart from PCX, there's also custom texture format for animated bitmaps (in
+FACE.DAT), and a few TIM images (in STAGE.DIR\init*\*.rd\*.r)
+
+STAGE.DIR\*\*.nd - texture archive (with .PCX files)
+STAGE.DIR\init*\*.rd - misc archive (with misc files)
+These archives contain several chunks in following format:
+ 000h 2 File ID (checksum on name?)
+ 002h 1 File Type (one of following chars: "p" for .nd, or "kors" for .rd)
+ 003h 1 Zero (00h)
+ 004h 4 Chunk Size (rounded to 4-byte boundary)
+ 008h .. Chunk Data
+The File Type can be:
+ .p PCX bitmap ;-in *\*.nd archives
+ .k Whatever ;\
+ .o Whatever "OARa" ; in init*\*.rd archives
+ .a Whatever ;
+ .r Misc (TIM and other stuff) ;/
+There can be 1-2 texture archives per STAGE.DIR folder (both having File
+ID=0000h) (probably due to a memory size limit: the game does probably load one
+archive with max 300Kbytes, relocate its contents to VRAM, then load the next
+archive, if any).
+
+STAGE.DIR\*\*.sw - wave archive
+There can be one or more .sw files per stage folder (eg. two sw's in
+"vr*\*.sw").
+ 000h 4 Unknown (800h or C00h) ;big-endian
+ 004h 4 Size of File List (N*10h) ;big-endian
+ 008h 8 Zerofilled
+ 010h N*10h File List (xx,xx,xx,00,00,00,00,7F,00,00,00,0F,00,19,0A,00)
+ ... 4 Unknown (40000h or 60000h) ;big-endian
+ ... 4 Size of SPU-ADPCM Data area ;big-endian
+ ... 8 Zerofilled
+ ... .. SPU-ADPCM Data area (indexed from File List)
+ File List entries:
+ 000h 4 Offset+Flags ;little-endian!
+ bit0-16 Offset (from begin of SPU-ADPCM Data area)
+ bit17 Unknown (0 or 1)
+ bit18 Unknown (1)
+ bit19-31 Unknown (0)
+ 004h 12 Whatever (always 00,00,00,7F,00,00,00,0F,00,19,0A,00)
+The unknown fields might contain volume, ADSR, pitch or the like?
+
+STAGE.DIR\*\*.se - sound effects? maybe short midi-like sequences or so?
+ 000h 80h*10h List (unused entries are 1x00000000h,3xFFFFFFFFh)
+ 800h .. Data (whatever, usually 14h or more bytes per list entry)
+ List entries:
+ 000h 1 Unknown (eg. 01h,10h,20h,A0h,80h,FFh) ;\
+ 001h 1 Number of Voices? (1..3) ; all zero for
+ 002h 1 Unknown (1 or 0) ; unused list entries
+ 003h 1 Unknown (2 or 0 or 1) ;/
+ 004h 4 Offset-800h for 1st Voice? ;-FFFFFFFFh=Unused
+ 008h 4 Offset-800h for 2nd Voice? (if any) ;-FFFFFFFFh=Unused
+ 00Ch 4 Offset-800h for 3rd Voice? (if any) ;-FFFFFFFFh=Unused
+ Data:
+ Seems to contain 4-byte entries (last entry being 00,00,FE,FF).
+
+STAGE.DIR\*\*.sm - whatever nested archives - sound music? mide-like?
+This does resemble a DOT1 Parent archive with 1-4 DOTLESS Child archives.
+Except, the offsets in Child archives are counted from begin of Parent archive.
+ Data:
+ Seems to contain 4-byte entries (last entry being 00,00,FE,FF).
+
+File IDs
+File IDs in STAGE.DIR (and maybe elsewhere, too) are computed as so:
+ sum=0,
+ for i=0 to len(filename)-1
+ sum=sum*20h+filename[i] ;\or so, 16bit overflows might be
+ sum=(sum+sum/10000h) AND FFFFh ;/cropped slightly differently
+Examples: "abst"=1706h, "selectvr"=8167h.
+Some filenames are empty (name="", ID=0000h).
+Some filenames do match up with the STAGE.DIR foldername.
+Some filenames do match up with strings in .sb file of current folder.
+Other filenames are unknown.
+
+CDROM File Archive DRACULA.DAT (Dracula)
+----------------------------------------
+
+Dracula - The Resurrection - DRACULA.DAT (180Mbyte)
+ 000h 4 Zero
+ 004h 4 Number of Entries (503h)
+ 008h 4 Zero
+ 00Ch 4 Random
+ 010h 10h Zero
+ 020h N*10h File List
+ ... .. Zeropadding to 800h-byte boundary
+ ... .. Fild Data area
+File List entries:
+ 000h 4 Offset/800h
+ 004h 4 Type (see below for info on different file types)
+ 008h 4 Filesize in bytes
+ 00Ch 4 Random (or 0 when Filesize=0)
+Most of the .DAT file consists of groups of 3 files (with type 01h/40h, 20h and
+400h; of which the files with type 20h and 400h may have Size=0=empty).
+ Type=00000001h Cubemap ;\either one of these
+ Type=00000040h Cubemap.empty ;/
+ Type=00000020h Cubemap.overlay? ;\these have size=0 when unused
+ Type=00000400h Cubemap.sounds ;/
+There are some general purpose files with other types at end of .DAT file:
+ Type=00000000h Archive with TIMs (Size=AB74h) (" RSC3.1V")
+ Type=00000004h Unknown (Size=16164h) (00000064h)
+ Type=00000008h Related to DRACULA1.STR (Size=1000h) (" RTS1.1V")
+ Type=00001000h Unknown (Size=2000h) ("BXFS1.1V")
+ Type=00008000h Unknown (Size=71Dh) (" CM1.1V")
+ Type=00020000h Unknown (Size=3B9h) (" GSM0.1V")
+ Type=02000000h Unknown (Size=0h) (empty)
+ Type=00000100h Related to DRACULA1.XA (Size=1000h) ("RAAX1.1V")
+ Type=00000010h Unknown (Size=450h) (" HYP0.1V")
+ Type=00100000h Unknown (Size=4014h) (" xFS1.1V") (x=A1h)
+ Type=00000080h Unknown (Size=258F4h) (00000010h)
+ Type=00000200h TIM (gui charset) (Size=6E9Eh) (TIM)
+ Type=00010000h TIM (gui buttons) (Size=10220h) (TIM)
+ Type=00040000h Unknown (Size=2C4h) (" TES0.1V")
+ Type=00002000h TIM (gui book pages) (Size=1040h) (TIM)
+ Type=00000800h Cubemap ;\as Type 01h, (Size=4092Ch) (" RIV3.1V")
+ Type=00004000h Cubemap ;/but [10h,14h]=0 (Size=4092Ch) (" RIV3.1V", too)
+Type 01h - Cubemap:
+ 000h 8 Name, ASCII, padded with leading spaces (eg. " RIV3.1V")
+ 008h 4 Something (0, 1 or 2) (unknown, this isn't number of list entries)
+ 00Ch 4 Zero
+ 010h 4 Offset to Ext data (ACh) ;\ext data
+ 014h 4 Size of Ext data (eg. 0 or 84h) ;/
+ 018h 6*4 Offsets to Side 0-5 ;\cubemap sides
+ 030h 6*4 Sizes of Side 0-5 (0, 10220h, or 10820h) ;/
+ 048h 44h Zerofilled
+ 08Ch 20h Name, ASCII (eg. "DEBUT0.VR", zeropadded)
+ 0ACh .. Ext Data (if any)
+ ... .. Cubemap TIM sides (if any)
+ Note: The cubemap TIMs have 100h or 400h colors (in the latter case: 100h
+colors for each quarter of the 8bpp bitmap).
+ Note: The TIMs can be arranged as 3D-cubemap with six sides, or as hires
+ 2D-bitmap (composed of four TIMs, and 2 empty TIMs with size=0).
+Type 40h - Empty Cubemap:
+ Same as Type 01h, but size is always 0ACh (and all seven Size entries are 0)
+Type 400h - Sound VAG's:
+ 000h 8 Name, ASCII, padded with leading spaces (eg. " XFS0.1V")
+ 008h 4 Zero
+ 00Ch 4 Number of Files (N) (max 10h)
+ 010h N*10h File List (100h bytes, zeropadded when less than 10h files)
+ 110h .. File Data (VAG files)
+ File List entries:
+ 000h 4 Unknown (55F0h, 255F0h or 20000h)
+ 004h 4 File ID (01010000h, increasing, or other when above=2xxxxh)
+ 008h 4 Offset in bytes ;\.VAG files
+ 00Ch 4 Filesize in bytes ;/
+Type 20h - Cubemap overlays, polygons, effects or so?:
+ 000h 8 Name, ASCII, padded with leading dot (eg. ".MNA4.1V")
+ 008h 4 Zero
+ 00Ch 4 Random
+ 010h 4 Unknown 01h
+ 014h 4 Total Number of 40h-byte blocks (01h..[018h]) (H)
+ 018h 4 Total Number of 120h-byte blocks (eg. 1Fh,31h) (N)
+ 01Ch 4 Total Number of 1Ch-byte blocks (eg. 1Eh, 50h, F7h) (M)
+ 020h 4 Unknown 0 or 1 (in file 4EAh)
+ 024h 4 Unknown 01h
+ 028h 6*4 Offsets to Side 0-5 (at end of file and up) (or 0) ;\cubemap
+ 040h 6*4 Sizes of Side 0-5 (10220h, or 10820h) (or 0) ;/sides
+ 058h H*40h 40h-byte blocks
+ ... N*120h 120h-byte blocks (related to offsets in 40h-byte blocks)
+ ... M*1Ch 1Ch-byte blocks (related to offsets in 120h-byte blocks)
+ ... .. Unknown data (related to offsets in 1Ch-byte blocks)
+ ... .. Ext data (related to Ext offsets in 40h-byte blocks)
+ FILE DOES END HERE!
+ (below is allocated in above header, but not actually stored in the file)
+ (maybe allocated as rendering buffer?)
+ ... - Cubemap TIM sides
+ The 40h-byte blocks are:
+ 000h 20h Name (eg. "FLAMMES", zeropadded)
+ 020h 4 Unknown 01h or 00h
+ 024h 4 Offset to 120h-byte blocks (usually 98h, or higher)
+ 028h 4 Unknown 00h
+ 02Ch 4 Number of 120h-byte blocks (01h..[018h])
+ 030h 4 Unknown 01h
+ 034h 4 Ext Offset ;\usually all zero
+ 038h 4 Ext Size (3C000h) ; (except, nonzero in file 4EAh)
+ 03Ch 4 Ext Random (checksum?) ;/
+ The 120h-byte blocks are:
+ 000h 18h*4 List with Offsets to 1Ch-byte blocks (usually 4 entries nonzero)
+ 060h 18h*4 List with Zeroes
+ 0C0h 18h*4 List with Numbers of 1Ch-byte blocks (usually max 4 entries)
+ The 1Ch-byte blocks are:
+ 000h 4 Unknown 04h
+ 004h 4 Width 20h or 10h
+ 008h 4 Height 20h or 10h or 30h
+ 00Ch 4 Unknown 60h or 10h
+ 010h 4 Unknown 00h or 30h
+ 014h 4 Offset to Unknown Data
+ 018h 4 Size of Unknown Data (Width*Height*1)
+Type 00h - TIMs:
+ 000h 8 Name (" RSC3.1V")
+ 008h 8 Zerofilled
+ 010h 4 Number of used entries (1Fh) (max 80h)
+ 014h 80h*4 Offset List (offsets to files) (A14h and up)
+ 214h 80h*4 Zero List (zerofilled)
+ 414h 80h*4 Size List (filesizes)
+ 614h 80h*4 Width List (0Ch,18h,34h,2Ch) (in pixels)
+ 814h 80h*4 Height List (0Ch,24h,34h,2Ch)
+ A14h .. Data (TIM files, with mouse pointers)
+
+CDROM File Archive Croc 1 (DIR, WAD, etc.)
+------------------------------------------
+
+Croc 1 (MagDemo02: CROC\*) (plus more files in retail version)
+CROCFILE.DIR and CROCFILE.1:
+ CROCFILE.DIR:
+ 000h 4 Number of Entries (N)
+ 004h N*18h File List
+ ... 4 Checksum (sum of all of the above bytes)
+ CROCFILE.1:
+ 000h .. File Data (referenced from .DIR)
+ File List entries:
+ 000h 0Ch Filename ("FILENAME.EXT", zeropadded if shorter)
+ 00Ch 4 File Size in bytes (can be odd) (including 8 byte for size/chksum)
+ 010h 4 File Offset in .1 file (unaligned, can be odd, increasing)
+ 014h 4 Zero (0)
+CROCFILE.DIR\MP*.MAP (and MAP files inside of MAP*.WAD and MP090-100_*.WAD):
+ 000h 4 Size-8 of whole file (or Size-0 for those in MP*.WAD)
+ 004h 4 Flags? (usually 0Ch or 14h)
+ 008h 1 Filename length (including trailing 00h, if any)
+ 009h .. Filename ("P:\CROC\EDITOR\MAPS\..\*.MAP") (+00h in MAP05*.WAD)
+ ... .. Unknown
+ ... 1 Description length
+ ... .. Description (eg. "Default New Map")
+ ... .. Unknown
+ ... (4) Checksum of whole file (sum of all bytes) (not in MP*.WAD)
+CROCFILE.DIR\*.WAD:
+ MAP*.WAD:
+ 000h 4 Size-8 of whole file
+ 004h .. MAP file(s) (each with size/checksum, same format as MP*.MAP)
+ ... 4 Checksum of whole file (sum of all of the above bytes)
+ CROC.WAD, CROCSLID.WAD, EXCLUDE.WAD, MP*.WAD, OPTIONS.WAD, SWIMCROC.WAD:
+ 000h 4 Size-8 of whole file
+ 004h 4 Offset-8 to SPU-ADPCM data area
+ 008h .. Data File area (model.MOD anim.ANI, bytecode.BIN, header.CVG, etc.)
+ ... .. SPU-ADPCM data area (if any, note in CROCSLID.WAD and OPTIONS.WAD)
+ The Data File area contains several "files" but doesn't have any directory
+ with filename/offset/size. The only way to find the separate files seems to
+ be to detect the type/filesize of each file, and then advance to next file
+ (bytecode.BIN files start with a size entry, but files like .MOD or .ANI
+ require parsing their fileheader for computing filesize).
+ Note: The PC version reportedly has .WAD files bundled with .IDX file (that
+ makes it easier to find files and filenames).
+ Note: The STRAT.DIR file contains a list of filenames used in .WAD files
+ (but lacks info on offset/size, so it isn't really useful).
+CROCFILE.DIR\*.BIN:
+ Sound.BIN Files (CROCFILE.DIR\AMBI*.BIN, MAP*.BIN, JRHYTHM.BIN, REVERB.BIN):
+ 000h 4 Size of .SEQ file ;\if any (not in REVERB.BIN)
+ 004h .. SEQ file (starting with ID "pQES") ;/
+ ... 4 Size of .VH file ;\always present
+ ... .. VH file (starting with ID "pBAV") ;/
+ ... .. VB file (sample data, SPU-ADPCM data, up to end of file)
+ Music.BIN files (MAGMUS.BIN, MUSIC.BIN):
+ 000h 4 Size-8 of whole file (118h)
+ 004h .. Increasing 32bit values ;sector numbers in PACK*.STR files or so?
+ ... 4 Unknown (2EEh or 258h) (aka 750 or 600 decimal)
+ ... .. Zeropadding
+ 11Ch 4 Checksum (sum of all of the above bytes)
+ Note: MUSIC.BIN has an extra copy (without chksum) in EXCLUDE.WAD\MUSIC.BIN
+ Ascii.BIN files (CREDITS*.BIN, MNAME.BIN):
+ 000h 4 Size-8 of whole file
+ 004h (2) Type or so? (02h,01h) (only in CREDITS*.BIN, not in MNAME.BIN)
+ ... .. Ascii strings (each string is: len,"text string",unknown)
+ ... 4 Checksum (sum of all of the above bytes)
+ Texture.BIN files (type 4) (STILLGO.BIN, STILLST.BIN, STILLTL.BIN):
+ 000h 2 Type (4=Texture/uncompressed, with 0Eh-byte list entries)
+ 002h 1 Zero (maybe Extra6byte as in type 5,6 Texture.BIN files)
+ 003h 2 Number of List entries (N) (always 4B0h in all three files)
+ 005h 2 Number of Texture Pages (usually 2)
+ 007h 2 Zero (maybe Unknown/Animation as in type 5,6 Texture.BIN files)
+ 009h N*0Eh Polygon List (?,?,?,?,?,?, x1,y1, x2,y1, x1,y2, x2,y2)
+ ... 40000h Texture Page uncompressed data (two pages, 20000h bytes each)
+ ... 4 Checksum (sum of all of the above bytes)
+ Texture.BIN files (type 5,6) (ENDTEXT*.BIN, FONT.BIN, FRONTEND.BIN,
+ OUTRO.BIN, PUBLISH.BIN, STILL*.BIN, TB*.BIN, TK*.BIN, TPAGE213.BIN):
+ 000h 4 Zero (0) (in TPAGE213.BIN: Size-8 of whole file)
+ 004h 2 Type (6=Texture/RLE16) (in TPAGE213.BIN: 5=Texture/uncompressed)
+ 006h 1 Extra6byte flag/size (0=None, 3=Extra6byte: TB*.BIN, TPAGE*.BIN)
+ ... (6) Extra6byte data (unknown purpose, only present when [006h]=3)
+ ... 2 Number of Polygon List entries (N)
+ ... 2 Number of Texture Pages (usually 1) (in TK*_ENM.BIN: usually 2)
+ ... 2 Number of Unknown Blocks (0=None, or 1,2,4,8)
+ ... (..) Unknown Block(s), if any
+ ... 2 Number of Animation Blocks (0=None)
+ ... (..) Animation Block(s), if any
+ ... N*0Ch Polygon List (?,?,?,?, x1,y1, x2,y1, x1,y2, x2,y2) ;x,y or y,x?
+ ... (4) Texture Page compressed size (T1) ;\only when [004h]=Type=6
+ ... (T1) Texture Page compressed data ;/
+ ... (4) Texture Page compressed size (T2) ;\only when [004h]=Type=6
+ ... (T2) Texture Page compressed data ;/ and NumPages=2
+ ... 20000h Texture Page uncompressed data ;-only when [004h]=Type=5
+ ... 4 Checksum (sum of all of the above bytes)
+ Unknown Block(s):
+ (Unknown purpose, each Unknown Block has the format shown below)
+ 000h 2 Unknown (looks like some index value, different for each entry)
+ 002h 2 Number of Unknown Items (eg. 1 or 2 or 4)
+ 004h .. Unknown Items (NumItems*6 bytes) (three halfwords each?)
+ Animation Block(s):
+ (This is supposedly used to update portions of the Texture Page for
+ animated textures, each Animation Block has the format shown below)
+ 000h 2 Number of Bitmap Frames in this Animation (usually 8)
+ 002h 2 Bitmap Width (in halfword units)
+ 004h 2 Bitmap Height
+ 006h 2 Unknown (1 or 3) ;\
+ 008h 2 Unknown (C10h, CC8h, 1E8h, or xxxh) ; maybe vram X,Y address?
+ 00Ah 2 Unknown (0) ;/
+ 00Ch .. Bitmap Frames (Width*2*Height*NumFrames bytes, uncompressed)
+ Croc 1 RLE16 compression:
+ This is using unsigned little-endian 16bit LEN/DATA pairs, LEN can be:
+ 0000h..7FFFh --> Load one halfword, fill 1..8000h halfwords
+ 8000h..FFFFh --> Copy 1..8000h uncompressed halfwords
+ BUG: Texture pages should be 20000h bytes (256x256 halfwords), but for
+ whatever reason, the size of decompressed data can be 1FFEAh, 1FFF0h,
+ 1FFFAh, 20000h, or 20002h.
+ Bytecode.BIN (inside of .WAD files):
+ 000h 4 Size of whole file
+ 004h .. Whatever bytecode (starting with initial 16bit program counter?)
+ Unknown.BIN (last 1-2 file(s) in EXCLUDE.WAD file):
+ 000h 4 Number of entries (N)
+ 004h N*18h Whatever
+ ... 4 Checksum (sum of above bytes)
+ Unknown purpose, retail version has one such file (with 0Ah entries), demo
+ version has two such files (with 0Ah and 4Eh entries. The files start with:
+ 0A,00,00,00,00,00,00,00,00,00,64,00,00,00,EB,FF,... ;demo+retail
+ 4E,00,00,00,00,00,64,00,00,00,50,00,00,00,64,00,... ;demo
+CROCFILE.DIR\*.MOD
+ Demo version has one .MOD file in CROCFILE.DIR (retail has more such files):
+ 000h 2 Number of Models (N) (1 or more) (up to ECh exists) ;\header
+ 002h 2 Flags (0 or 1) ;/
+ 004h N*Var SubHeadersWithData ;see below ;-data
+ ... 4 Checksum (sum of all of the above bytes) ;-checksum
+ SubHeadersWithData(N*Var):
+ 004h 4 Radius ;\
+ 008h 48h Bounding Box[9*8] (each 8byte are 4x16bit: X,Y,Z,0) ; for each
+ 050h 4 Number of Vertices (V) ; model
+ 054h V*8 Vectors (4x16bit: X,Y,Z,0) ;
+ ... V*8 Normals (4x16bit: X,Y,Z,0) ;
+ ... 4 Number of Faces (F) (aka Polygons?) ;
+ ... F*14h Faces (8x16bit+4x8bit: X,Y,Z,0,V1,V2,V3,V4, Tex/RGB) ;
+ ... 2 Number of collision info 1? (X) ;\ ;
+ ... 2 Number of collision info 2? (Y) ; only if ;
+ ... X*2Ch Collision info 1? ; Flags.bit0=1 ;
+ ... Y*2Ch Collision info 2? ;/ ;/
+ There are further .MOD models inside of .WAD files, with slightly
+ re-arranged entries (and additional reserved/garbage fields):
+ 000h 2 Number of Models (N) (1 or more) (up to ECh exists) ;\
+ 002h 2 Flags (0 or 1) ; header
+ 004h 4 Reserved/garbage (usually 224460h) (or 22C9F4h/22DF54h) ;/
+ 008h (4) Number of Models WITH Data arrays (M) ;\
+ 00Ch (M*2) Model Numbers WITH Data arrays (increasing, 0..N-1) ; ext.hdr
+ ... (..) Padding to 4-byte boundary (garbage, usually=M) ;/
+ ... N*68h Subheader(s) ;see below ;-part 1
+ ... N*Var DataArray(s) ;see below ;-part 2
+ Subheaders(N*68h):
+ 000h 4 Radius ;\
+ 004h 48h Bounding Box[9*8] (each 8byte are 4x16bit: X,Y,Z,0) ; for each
+ 04Ch 4 Number of Vertices (V) ; model
+ 050h 4 Reserved/garbage (usually 0022xxxxh) ;
+ 054h 4 Reserved/garbage (usually 0022xxxxh) ;
+ 058h 4 Number of Faces (F) (aka Polygons?) ;
+ 05Ch 4 Reserved/garbage (usually 0022xxxxh) ;
+ 060h 2 Number of collision info1? (X) ;
+ 062h 2 Number of collision info2? (Y) ;
+ 064h 4 Reserved/garbage (usually 0022xxxxh) or xxxxxxxxh) ;/
+ DataArrays(N*Var) with sizes V,F,X,Y from corresponding Subheader:
+ (if ext.hdr is present, then below exists only for models listed in ext.hdr)
+ 000h V*8 Vectors (4x16bit: X,Y,Z,0) ;\
+ ... V*8 Normals (4x16bit: X,Y,Z,0) ; for each
+ ... F*14h Faces (8x16bit+4x8bit: X,Y,Z,0,V1,V2,V3,V4, Tex/RGB) ; model
+ ... X*2Ch Collision info 1? ;
+ ... Y*2Ch Collision info 2? ;/
+ The ext.hdr mentioned above exists only in some .MOD files (usually in one of
+ the last chunks of MP*.WAD). Files with ext.hdr have N>1, Flags=1 (but files
+ without ext.hdr can also have those settings). Files with ext.hdr do usually
+ have uncommon garbage values at hdr[4], which isn't too helpful for detection.
+ The only way to detect models with ext.hdr seems to be to check if the ext.hdr
+ contains valid increasing entries in range 0..N-1.
+ WAD's that do contain a model with ext.hdr do usually also contain an extra
+ 100h-byte file, that file contains N bytes for model 0..N-1 (plus zeropadding
+ to 100h-byte size), the bytes are supposedly redirecting models without Data
+ Arrays to some other data source.
+ The 100h-byte files don't have any header or checksum, they contain up to 9Ch
+ entries (so there's always some zeropadding to 100h), the existing 100h-byte
+ files contain following values in first 4 bytes (as 32bit value):
+ 04141401h, 0C040017h, 01010101h, 09030503h, 0A0B0A0Bh, 03020102h, 0C060900h,
+ 00060501h, 04040201h, 01010203h, 01030201h, 05000302h, 0C040317h, or Zero.
+ To distinguish from other files: BIN/MAP files start with a 4-byte aligned
+ Size value; if Size=0 or (Size AND 3)>0 or Size>RemainingSize then it's
+ probably a 100h-byte file. Best also check if last some bytes are zeropadded.
+ Exceptions:
+ Retail MP090..MP100_*.WAD has model with ext.hdr, but no 100h-byte file
+ Demo MP041_00.WAD has model with ext.hdr, with zerofilled 100h-byte file
+ Note: Some models have ALL models listed in ext.hdr (which is about same as
+ not having any ext.hdr at all; except, they ARE bundled with 100h-byte file).
+CROCFILE.DIR\MP*.DEM
+ Some (not all) MP*.WAD files are bundled with MP*.DEM files, supposedly
+ containing data for demonstration mode. There are two versions:
+ demo version: size 2584h (9604 decimal) (some files with partial checksum)
+ retail version: size 0E10h (3600 decimal) (without checksum)
+CROCFILE.DIR\CROCWALK.ANI:
+ Animation data, there is only one such file in CROCFILE.DIR:
+ 000h 2 Value (100h)
+ 002h 2 Number of Triggers (T) (2)
+ 004h (T*2) Trigger List (with 2x8bit entries: FrameNo, TriggerID)
+ ... .. Probably, Padding to 4-byte boundary (when T=odd)
+ ... 4 Number of entries 1 (X)
+ ... X*18h Whatever Array 1
+ ... 4 Number of entries 2 (Y) (usually/always 64h)
+ ... X*Y*4 Whatever Array 2
+ ... 4 Number of entries 3 (Z) (usually/always 0Ah)
+ ... X*Z*18h Whatever Array 3
+ There are further .ANI files inside of .WAD files:
+ 000h 2 Value (100h or 200h) ;Animation Speed?
+ 002h 2 Number of Triggers (T) (0, 1, 2, 3, 5, or 9)
+ 004h 4 Garbage/Pointer (usually 224460h) (or zero)
+ 008h 4 Number of entries 1 (X) (1 or more) ;Num Frames
+ 00Ch 4 Garbage/Pointer (usually 22C9F4h) (or 224460h or 22DF54h)
+ 010h 4 Number of entries 2 (Y) (usually 64h) (or 0) ;Num Vertices (?)
+ 014h 4 Garbage/Pointer
+ 018h 4 Number of entries 3 (Z) (usually 0Ah) (or 6 or 9)
+ 01Ch 4 Garbage/Pointer
+ 020h (T*2) Trigger List (with 2x8bit entries: FrameNo, TriggerID)
+ ... .. Padding to 4-byte boundary (garbage, usually=X)
+ ... X*18h Whatever Array 1
+ ... X*4 Garbage/Pointers (0021EE74h,0021EE74h,xxx,...)
+ ... X*Y*4 Whatever Array 2 ;Vertex 3x10bit? ;only if Y>0
+ ... (X*4) Garbage/Pointers (0021EE74h,0021EE74h,xxx,...) ;only if Y>0
+ ... X*Z*18h Whatever Array 3
+CROCFILE.DIR\TCLD.CVG:
+ There is only one such file in CROCFILE.DIR:
+ 000h 4 Size-8 of whole file
+ 004h 4 Unknown (0)
+ 008h 4 Unknown (1)
+ 00Ch .. SPU-ADPCM data
+ ... 4 Checksum (sum of all of the above bytes)
+ There are further .CVG files inside of .WAD files, these consist of two
+ parts; 0Ch-byte Headers (in the data file area), and raw SPU-ADPCM data
+ (in the spu-adpcm data area at end of the .WAD file):
+ Header(0Ch):
+ 000h 4 Size+8 of data part
+ 004h 4 Unknown (0)
+ 008h 4 Unknown (0 or 1)
+ Data(xxxx0h):
+ 000h .. SPU-ADPCM data (starting with sixteen 00h bytes)
+STRAT.DIR (in retail version with extra copy in CROCFILE.DIR\STRAT.DIR):
+ This file contains a list of filenames for files inside of .WAD files, but
+ it does NOT tell where those files are (in which WAD at which offset).
+ 000h 4 Number of Entries (N)
+ 004h N*xxh File List (retail=14h bytes, or demo=18h bytes per entry)
+ ... 4 Checksum (sum of all of the above bytes)
+ List entries are:
+ demo: entrysize=18h ;Filename(0Ch)+Size(4)+Zeroes(8)
+ retail: entrysize=14h ;Filename(0Ch)+ Zeroes(8)
+ The list contains hundreds of filenames, with following extensions:
+ *.BIN byte-code strategies
+ *.MOD models
+ *.ANI animations
+ *.CVG spu-adpcm voice data
+ These "filenames" seem to be actually solely used as "memory handle names":
+ MemoryHandle(#1) = LoadFile("FILENAME.BIN") ;<-- names NOT used like this
+ MemoryHandle("FILENAME.BIN") = LoadFile(#1) ;<-- names used like this
+PACK*.STR (retail version only):
+ Huge files with XA-ADPCM audio data
+MAGMUS.STR (demo version only):
+ Huge mis-mastered 24Mbyte file (contains several smaller XA-ADPCM blocks,
+ accidentally stored in 800h-byte FORM1 data sectors, instead of 914h-byte
+ FORM2 audio sectors).
+ARGOLOGO.STR, FOXLOGO.STR
+ MDEC movies
+COPYRIGHT.IMG, WARNING.IMG
+ Raw bitmaps (25800h bytes, uncompressed, 320x240x16bpp)
+CUTS\*.AN2 (looks like cut-scenes with polygon-streaming):
+--> CDROM File Video Polygon Streaming
+Note: MOD/ANI files contain many Reserved/Garbage/Pointer entries which are
+replaced by pointers after loading (the initial values seem to have no purpose;
+they are aften set to constants with value 002xxxxxh which could be useful for
+file type detection, but they vary in different game versions).
+See also:
+https://github.com/vs49688/CrocUtils/ (for PC version, PSX support in progress)
+
+CDROM File Archive Croc 2 (DIR, WAD, etc.)
+------------------------------------------
+
+Croc 2 (MagDemo22: CROC2\CROCII.DIR\T*.WAD+DEM)
+Disney's The Emperor's New Groove (MagDemo39: ENG\KINGDOM.DIR\T*.WAD+DEM)
+Disney's Aladdin in Nasira's Rev. (MagDemo46: ALADDIN\ALADDIN.DIR\T*.WAD+DEM)
+Alien Resurrection, and Harry Potter 1 and 2 ... slightly different format?
+Overall .WAD format:
+ 000h 4 Total Filesize+/-xx (-4 or +800h or +1800h)
+ 004h 4+4+.. XSPT Chunk ;Textures
+ ... 4+4+.. XSPS Chunk ;SPU-ADPCM Sound (if any, not in all .WAD's)
+ ... 4+4+.. XSPD Chunk ;...whatever Data...?
+ ... 4+4 DNE Chunk ;End marker (in Harry Potter: with data!)
+XSPT Chunk (Textures):
+ 000h 4 Chunk Name "XSPT" (aka TPSX backwards)
+ 004h 4 Chunk Size (excluding 8-byte Name+Size)
+ 008h 4 Chunk Flags (02h or 06h or 0Eh) ;02h in Croc 2
+ 00Ch (20h) Name (eg. "Default new map", zeropadded) ;\if Flags bit2=1
+ ... (804h) Unknown ... SAME as in XSPD chunk !!! ;/
+ ... 4 Number of List 1 entries (N1) (xxh..xxxh) ;\
+ ... 4 Number of Texture Pages (1..4) ; List 1 and NumPages
+ ... N1*0Ch List 1 Whatever (6B 2F xx 00..) ;/
+ ... 4 Number of List 2 entries (N2) (0..xxh) ;\
+ ... 4 Unknown (2 or 7) ; List 2
+ ... N2*04h List 2 Whatever (halfwords?) (if N2>0) ;/
+ ... (5*C00h) Whatever, 5*C00h, Palette+Stuff? ;-if Flags bit3=1
+ ... .. RLE16 compressed Texture Pages ;-Texture bitmap
+ RLE16 Texture notes:
+ Compressed data consists of signed little-endian 16bit LEN+DATA pairs:
+ LEN=0000h --> invalid/unused
+ LEN=0001h..7FFFh --> copy LEN halfwords from src
+ LEN=8000h..FFFFh --> load ONE halfword as fillvalue, fill -LEN halfwords
+ Compressed size is everything up to end of XSPT chunk
+ Decompressed size is 20000h*NumTexturePages (=20000h,40000h,60000h or 80000h)
+ That is: Width=256 halfwords, height 256*NumTexturePages lines. There seems
+ to be only one RLE16 compression block for all Texture Pages, rather than one
+ RLE16 block for each Page.
+ BUG #1: Decompressed data in Aladding/Emperor does often contain only
+ 1FFFEh,3FFFEh,5FFFEh,7FFFEh bytes (the decompressed data has correct size
+ when appending ONE halfword with random/zero value).
+ BUG #2: Compressed data in Croc 2 ends with a RLE16 length value (-LEN), but
+ lacks the corresponding RLE16 filldata (the decompressed data is 7FFFEh when
+ filling those LEN halfwords with random/zero values).
+XSPS Chunk (SPU-ADPCM Sound) (if any, isn't present in all .WAD files):
+ 000h 4 Chunk Name "XSPS" (aka SPSX backwards) ;\
+ 004h 4 Chunk Size (excluding 8-byte Name+Size) ; header
+ 008h 4 Chunk Flags (0 or 3 or 7) ;/
+ 00Ch 4 Number of Sounds (N1) (1..xxh) ;\always present
+ 010h N1*14h Sound List ;/
+ ... (4) VAB/VH Size ;\if Flags=3 or 7
+ ... (..) VAB/VH Header ;/ (bit0 or bit1?)
+ ... (4) Unknown (2 or 4) ;-if Flags=3 or 7
+ ... (4) Whut (N2) ;\if Flags.bit2=1
+ ... (N2*10h) Whut List (4 words: xxh,10h,xxxx00h,xxxx0h);/
+ ... 4 Size of all Part 1 Sound Data blocks ;\always
+ ... .. SPU-ADPCM Sound Data (referenced from Sound List) ;/
+ ... (4) Size of all Part 2 Sound Data blocks (+8) ;\if Flags=
+ ... (..) SPU-ADPCM Sound Data (referenced from Sound List?) ; 3 or 7
+ ... (8) Zero ;/
+ Sound List entries (as in FESOUND.WAD):
+ 000h 4 Sample Rate in Hertz (AC44h=44100Hz, 5622h=22050Hz, 3E80h=16000Hz)
+ 004h 2 Sample Rate Pitch (1000h=44100Hz, 0800h=22050Hz, 05CEh=16000Hz)
+ 006h 2 Unknown (7Fh)
+ 008h 4 Unknown (1) (1) (8)
+ 00Ch 4 Unknown (42008Fh) (1FC0001Fh) (40008Fh)
+ 010h 4 Filesize (xxx0h) (xxx0h)
+XSPD Chunk:
+ 000h 4 Chunk Name "XSPD" (aka DPSX backwards)
+ 004h 4 Chunk Size (excluding 8-byte Name+Size)
+ 008h 4 Flags-and/or-other stuff ? (eg. 00000094h or 0A801094h)
+ 00Ch 804h Unknown ... SAME as in XSPT chunk !!!
+ 810h .. Unknown ...
+DNE Chunk (End marker):
+ 000h 4 Chunk Name " DNE" (aka END backwards)
+ 004h 4 Chunk Size (0) (except, in Harry Potter: nonzero)
+ ... .. Data (usually none such) (except, in Harry Potter: with data!)
+Additional DEM files (always 1774h bytes) (if any, not all .WAD's have .DEM's):
+ 000h 4 Number of entries (N) (always 2EEh, aka 750 decimal)
+ 004h N*8 Whatever entries... maybe data for demonstration mode?
+See also:
+http://wiki.xentax.com/index.php/Argonaut_WAD
+
+CDROM File Archive Headerless Archives
+--------------------------------------
+
+Headerless Archives
+Some games use files that contain several files badged together. For example,
+ PSX Resident Evil 2, COMMON\DATA\*.DIE contains TIM+VAB badged together
+ PSX Resident Evil 2, COMMON\DATA\*.ITP contains 1000h-byte aligned TIMs
+ Blaster Master, DATA\MENU\*\*.PRT contains three smaller TIMs badged together
+ Blaster Master, DATA\MENU\*\*.BG contains three bigger TIMs badged together
+ Misadventures of Tron Bonne, KATWA\*.BIN contains headerless archives (with
+TIMs and audio)
+ Headerless BSS files contain several BS files with huge padding inbetween
+To some level one could detect & resolve such cases, eg. TIM contains
+information about the data block size(s), if the file is bigger, then there may
+be further file(s) appended.
+Some corner cases may be: Files with odd size may insert alignment padding
+before next file. Archives with 800h-byte filesize resolution will have
+zeropadding (or garbage) if the real size isn't a mutiple of 800h. Regardless
+of that two cases, archives may use zeropadding to 800h-byte or even
+10000h-byte boundaries (as workaround one could skip zeroes until reaching a
+well-aligned nonzero word or double word (assuming that most files start with
+nonzero values; though not always, eg. raw ADPCM or raw bitmaps).
+
+CDROM File Compression
+----------------------
+
+Compressed Bitmaps
+ .BS used by several games (and also in most .STR videos)
+ .GIF used by Lightspan Online Connection CD
+ .JPG used by Lightspan Online Connection CD
+ .BMP with RLE4 used by Lightspan Online Connection CD (MONOFONT, PROPFONT)
+ .BMP with RLE8+Delta also used by Online Connection CD (PROPFONT\ARIA6.BMP)
+ .PCX with RLE used by Jampack Vol. 1 (MDK\CD.HED\*.pcx)
+ .PCX with RLE used by Hot Wheels Extreme Racing (MagDemo52: US_01293\MISC\*)
+ .PCX with RLE used by Metal Gear Solid (slightly corrupted PCX files)
+
+Compressed Audio
+ .XA uses XA-ADPCM (and also used in .STR videos)
+ .VAG .VB .VAB uses SPU-ADPCM
+
+Compressed Files
+--> CDROM File Compression LZSS (Moto Racer 1 and 2)
+--> CDROM File Compression LZSS (Dino Crisis 1 and 2)
+--> CDROM File Compression LZSS (Serial Experiments Lain)
+--> CDROM File Compression ZOO/LZSS
+--> CDROM File Compression Ulz/ULZ (Namco)
+--> CDROM File Compression SLZ/01Z (chunk-based compressed archive)
+--> CDROM File Compression LZ5 and LZ5-variants
+--> CDROM File Compression PCK (Destruction Derby Raw)
+--> CDROM File Compression GT-ZIP (Gran Turismo 1 and 2)
+--> CDROM File Compression GT20 and PreGT20
+--> CDROM File Compression HornedLZ
+--> CDROM File Compression LZS (Gundam Battle Assault 2)
+--> CDROM File Compression BZZ
+--> CDROM File Compression RESOURCE (Star Wars Rebel Assault 2)
+--> CDROM File Compression TIM-RLE4/RLE8
+--> CDROM File Compression RLE_16
+--> CDROM File Compression PIM/PRS (Legend of Mana)
+--> CDROM File Compression BPE (Byte Pair Encoding)
+--> CDROM File Compression RNC (Rob Northen Compression)
+--> CDROM File Compression Darkworks
+--> CDROM File Compression Blues
+--> CDROM File Compression Z (Running Wild)
+--> CDROM File Compression ZAL (Z-Axis)
+--> CDROM File Compression EA Methods
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+--> CDROM File Compression LArc/LHarc/LHA (LZS/LZH)
+Some other archvies that aren't used by any PSX games, but, anyways...
+--> CDROM File Compression ARJ
+--> CDROM File Compression ARC
+--> CDROM File Compression RAR
+--> CDROM File Compression ZOO
+--> CDROM File Compression nCompress.Z
+--> CDROM File Compression Octal Oddities (TAR, CPIO, RPM)
+--> CDROM File Compression MacBinary, BinHex, PackIt, StuffIt, Compact Pro
+
+Compressed Archives
+Some Archives have "built-in" compression.
+--> CDROM File Archive WAD (Doom)
+--> CDROM File Archive BIGFILE.DAT (Gex - Enter the Gecko)
+
+CDROM File Compression LZSS (Moto Racer 1 and 2)
+------------------------------------------------
+
+Moto Racer 1 ("LZSS" with len+2) (MagDemo03: MRDEMO\IMG\*.TIM)
+Moto Racer 2 ("LZSS" with len+3) (MagDemo16: MR2DEMO\IMG\*.TIM and .TPK)
+ 000h 4 ID "LZSS"
+ 004h 4 Decompressed Size
+ 008h .. Compressed Data
+This LZSS variant is unusually using 6bit len and 10bit disp. And, there are
+two versions: Moto Racer 1 uses len+2, and Moto Racer 1 uses len+3. There is no
+version information in the header, one workaround is to decompress the whole
+file with len+2, and, if the resulting size is too small, retry with len+3.
+Observe that the attempt with len+2 may cause page faults (eg. if the sum of
+len values is smaller than disp; so allocate some extra space at begin of
+compression buffer, or do error checks),
+ @@collect_more:
+ flagbits=[src]+100h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ flagbits=flagbits SHR 1
+ if zero then goto @@collect_more
+ if carry=1 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ disp=([src]+[src+1]*100h) AND 3FFh, len=([src+1]/4)+2_or_3, src=src+2
+ if disp=0 then goto @@decompress_done
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+CDROM File Compression LZSS (Dino Crisis 1 and 2)
+-------------------------------------------------
+
+Dino Crisis 1 and 2 (PSX\DATA\*.DAT and *.DBS and *.TEX, File type 7,8)
+Dino Crisis LZSS Decompression for files with type 7 and 8:
+ @@collect_more:
+ flagbits=[src]+100h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ flagbits=flagbits SHR 1
+ if zero then goto @@collect_more
+ if carry=1 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ disp=[src]+[src+1]*100h AND FFFh, len=[src+1]/10h+2, src=src+2
+ if disp=0 then error
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ if src<src_end then goto @@decompress_lop
+ ret
+The compressed file & archive header don't contain any info on the decompressed
+size (except, for compressed bitmaps, the archive header does contain
+width/height entries, nethertheless the decompressed file is usually BIGGER
+then width*height*2 (it can contain padding, plus 8 bytes).
+
+CDROM File Compression LZSS (Serial Experiments Lain)
+-----------------------------------------------------
+
+Serial Experiments Lain is using LZSS compression for TIMs (in SITEA.BIN,
+SITEN.BIN), and for Transparency Masks (in LAPKS.BIN).
+
+Serial Experiments Lain (7MB SITEA.BIN on Disc 1, 5MB SITEB.BIN on Disc 2)
+These are huge 5-7 Mbyte files with hundreds of chunks. Each chunk contains one
+compressed TIM.
+ Each chunk is having this format:
+ 000h 4 Chunk ID "napk"
+ 004h 4 Decompressed size
+ 008h .. LZSS compressed TIM data
+ ... .. Zeropadding to 800h-byte boundary
+Unknown how the game is accessing chunks (there is no chunk size info, so one
+would need read the whole file (or at least first 4-byte of each 800h-byte
+sector) for finding chunks with ID="napk").
+
+Serial Experiments Lain (LAPKS.BIN on Disc 1 and 2)
+This a huge 14Mbyte file with 59 chunks. Each chunk contains one or more 24bpp
+.BS images with black background (the images in each chunk are forming a short
+animation sequence; width/height may vary because all images are cropped to
+rectangles containing non-black pixels).
+ Each chunk is having this format:
+ 000h 4 Chunk ID "lapk"
+ 004h 4 Chunk size (excluding 8-byte chunk header, excluding zeropadding)
+ 008h 4 Number of Files in this Chunk (N)
+ 00Ch N*0Ch File List
+ ... .. File Data (bitmaps in .BS v0 format with uncommon headers)
+ ... .. Zeropadding to 800h-byte boundary
+ File List entries:
+ 000h 4 Offset in bytes (zerobased, from begin of File Data area)
+ 004h 2 Bitmap Width/2 + some 3bit value in LSBs?
+ 006h 2 Bitmap Height
+ 00Ch 4 Zero
+ File Data (bitmaps in .BS v0 format with uncommon headers):
+ 000h 2 Bitmap Width
+ 002h 2 Bitmap Height
+ 004h 2 Quant for Y1,Y2,Y3,Y4
+ 006h 2 Quant for Cr,Cb
+ 008h 4 Size of compressed BS Bitstream plus 4 ;Transparency at [008h]+0Ch
+ 00Ch 2 Size/2 of MDEC data (after huffman decompression, without padding)
+ 00Eh 2 BS Version (0) (actually MSBs of above Size, but it's always 0)
+ 010h .. BS Bitstream with DC and AC values (Huffman compressed MDEC data)
+ ... 4 Transparency Mask Decompressed Size (Width*Height*2/8) (=2bpp)
+ ... .. Transparency Mask LZSS-compressed data
+BUG: The chunksize at C3A800h is set to 4C614h but should be 4D164h (the next
+chunk starts at C88000h).
+Unknown how the game is accessing chunks (crawling all chunks would be
+exceptionally slow due to CDROM seek times, and won't work with the BUGGED
+chunksize).
+
+Decompression function
+This LZSS variant is unusually using 8bit len and 8bit disp.
+ dst_end=dst+[src], src=src+4 ;decompressed size
+ @@collect_more:
+ flagbits=([src] SHL 24)+800000h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ if dst=dst_end then goto @@decompress_done
+ flagbits=flagbits SHL 1 ;32bit shift with carry-out/zeroflag
+ if zero then goto @@collect_more
+ if carry=0 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ disp=[src]+1, len=[src+1]+3, src=src+2
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+CDROM File Compression ZOO/LZSS
+-------------------------------
+
+Jarret & LaBonte Stock Car Racing (MagDemo38: WTC\*.ZOO)
+ 0000h 4 Decompressed Size ;\1st sector
+ 0004h 7FCh Garbage ;/
+ 0800h 4 Decompressed Size (same as above) ;\2nd sector
+ 0804h 7FCh LZSS compressed data, part 1 ;/
+ 1000h 800h LZSS compressed data, part 2 ;-3rd sector
+ 1800h 800h LZSS compressed data, part 3 ;-4th sector
+ ... .. etc.
+Note: The file format & compression method is unrelated to ZOO archives (to
+distinguish between the formats: ZOO archives have [0014h]=FDC4A7DCh, the
+ZOO/LZSS files have [0014h]=Garbage).
+The decompressed WTC\*.ZOO files can contain large TIMs, or chunk-based
+archives (where each chunk can contain one or more small TIMs), or other stuff.
+
+Decompression function
+ decompress_file:
+ if LittleEndian32bit[src+14h]=FDC4A7DCh then goto error ;refuse ZOO archives
+ if LittleEndian32bit[src]<>LittleEndian32bit[src+800h] then goto error
+ curr=src+800h
+ src=curr+4
+ @@sector_lop:
+ call decompress_sector
+ curr=curr+800h
+ src=curr
+ if src<src_end then goto @@sector_lop
+ ret
+ ;---
+ decompress_sector:
+ @@collect_more:
+ flagbits=([src] SHL 24)+800000h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ flagbits=flagbits SHL 1 ;32bit shift with carry-out/zeroflag
+ if zero then goto @@collect_more
+ if carry=0 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ disp=[src]*100h+[src+1], src=src+2
+ if disp=FFFFh then goto @@decompress_done
+ len=(disp/800h)+3, disp=(disp AND 7FFh)+1
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+CDROM File Compression Ulz/ULZ (Namco)
+--------------------------------------
+
+Ulz/ULZ uses fairly normal LZSS compression, unusually with variable Len/Disp
+ratio, three separate data streams (flg/lz/dta), and rather weird end check in
+version=0.
+
+Ulz Format (Ace Combat 3 Electrosphere, Namco)
+Ulz Format (Klonoa, MagDemo08: KLONOA\FILE.IDX\*)
+ 000h 4 ID ("Ulz",1Ah) (parts lowercase)
+ 004h 3 Decompressed Size in bytes
+ 007h 1 Version (0 or 2)
+ 008h 3 Offset to Uncompressed data <-- reportedly can be 0 in version=0?
+ 00Bh 1 Number of Disp bits (DispBits=N, LenBits=16-N) (usually 0Ah..0Dh)
+ 00Ch 4 Offset to Compressed data
+ 010h .. Compression Flags (32bit entries)
+ ... .. Uncompressed data (8bit entries)
+ ... .. Zeropadding to 4-byte boundary
+ ... .. Compressed data (16bit entries)
+Most files use version=2 (eg. US:ACE.BPH\0006h\000Fh contains DOT1 with TIMs).
+Some files use version=0 (eg. US:ACE.BPH\0048h\*\* contains TIMs).
+
+ULZ Format (Time Crisis, Namco)
+ 000h 4 ID ("ULZ",1Ah) (all uppercase)
+ 004h 2 Zero
+ 006h 1 Version (0 or 2)
+ 007h 1 Number of Disp bits (DispBits=N, LenBits=16-N) (usually 0Ah..0Dh)
+ 008h 4 Offset to Uncompressed data
+ 00Ch 4 Offset to Compressed data
+ 010h 4 Decompressed Size in bytes
+ 014h .. Compression Flags (32bit entries)
+ ... .. Uncompressed data (8bit entries)
+ ... .. Zeropadding to 4-byte boundary
+ ... .. Compressed data (16bit entries)
+Most files use version=2 (eg. EUR: AD*\TIM*.FHT\*)
+Some files use version=0 (eg. EUR: AD4\TIM0_0.FHT\0018h, 0019h)
+
+Ulz/ULZ Decompression Function
+ if [src+00h]="Ulz",1Ah then
+ version = Byte[src+07h]
+ disp_bits = Byte[src+0Bh]
+ dst_end = LittleEndian24bit[src+04h] + dst
+ src_dta = LittleEndian24bit[src+08h] + src
+ src_lz = LittleEndian32bit[src+0Ch] + src
+ src_flg = src + 10h
+ add_len = 3
+ flg_1st = 31 ;process flag bit31 first
+ if [src+00h]="ULZ",1Ah then
+ version = Byte[src+06h]
+ disp_bits = Byte[src+07h]
+ src_dta = LittleEndian32bit[src+08h] + src
+ src_lz = LittleEndian32bit[src+0Ch] + src
+ dst_end = LittleEndian32bit[src+10h] + dst
+ src_flg = src + 14h
+ add_len = 2
+ flg_1st = 0 ;process flag bit0 first
+ collected = 80000000h ;initially empty, plus stop bit
+ @@decompress_lop:
+ if version=2 AND dst=dst_end then goto @@decompress_done
+ flag = collected AND 80000000h
+ collected=collected*2
+ if collected=0
+ collected = LittleEndian32bit[src_flg], src_flg=src_flg+4
+ if flg_1st=0 then ReverseBitOrder(collected) ;or make custom/faster code
+ flag = collected AND 80000000h
+ if version=0 AND collected=0 then goto @@decompress_done
+ if version=0 then collected=collected*2 ;<-- has implied stop bit
+ if version=2 then collected=collected*2 + 1 ;<-- shift-in stop bit
+ if flag=0 ;compressed
+ disp = LittleEndian16bit[src_lz], src_lz=src_lz+2
+ len = (disp SHR disp_bits) + add_len
+ disp = (disp AND ((1 shl disp_bits)-1)) + 1
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ else ;uncompressed
+ [dst]=[src_dta], dst=dst+1, src_dta=src_dta+1
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+Note: Version=2 has 32 flags per 32bit. Version=0 has 31 flags and 1 stop bit
+per 32bit, plus 32 null bits at end of data (which is all rather wasteful,
+there's no good reason to use version=0).
+
+CDROM File Compression SLZ/01Z (chunk-based compressed archive)
+---------------------------------------------------------------
+
+SLZ/01Z files are Chunk-based archives with one or more compressed chunk(s).
+Used by Hot Shots Golf 2 (retail: DATA\F0000.BIN\*, MagDemo31/42:
+HSG2\MINGOL2.BIN\*)
+
+SLZ/01Z chunk headers
+The archive consists of Chunk(s) in following format:
+ 000h 3 ID (either "01Z" or "SLZ", both are used)
+ 003h 1 Method (00h=Uncompressed, 01h=LZSS, 02h=LZSS+FILL)
+ 004h 4 Compressed size (SIZ) (same as decompressed when Method=0)
+ 008h 4 Decompressed size
+ 00Ch 4 Distance to next chunk, if any (SIZ+10h+Align4, or 0=None)
+ 010h SIZ Compressed data
+
+SLZ/01Z decompression function:
+ method=byre[src+3]
+ len=word[src+8]
+ src=src+10h
+ if method=0 then
+ for i=1 to len, [dst]=[src], dst=dst+1, src=src+1, next i
+ goto @@decompress_done
+ dst_end = dst+len
+ @@collect_more:
+ flagbits=[src]+100h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ if method=2 AND dst=dst_end then goto @@decompress_done
+ flagbits=flagbits SHR 1
+ if zero then goto @@collect_more
+ if carry=1 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ disp=([src]+[src+1]*100h) AND 0FFFh, len=([src+1]/10h)+3, src=src+2
+ if method=1 AND disp=0 then goto @@decompress_done
+ if method=2 AND len=12h then ;special fill mode...
+ len=disp/100h+3, val=disp AND FFh ;len=3..12h
+ if len=3 then len=val+13h, val=[src], src=src+1 ;len=13h..112h
+ for i=1 to len, [dst]=val, dst=dst+1, next i ;len=4..112h
+ else
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+CDROM File Compression LZ5 and LZ5-variants
+-------------------------------------------
+
+Original LArc LZ5 (method "-lz5-")
+LZ5 was used by LArc compression tool from 1988/1989, decompression is also
+supported by LHarc/LHA. LZ5 is basically LZSS compression, but with some
+oddities:
+ LZ5 is often implemented with a ringbuf (instead of actual sliding window)
+ LZ5 uses absolute ringbuf indices (instead of relative sliding dest indices)
+ LZ5 requires the ringbuf to be initially prefilled with constants
+ LZ5 ringbuf is 1000h bytes tall and starts with write index FEEh
+LArc was discontinued in 1989, but LZ5-variants have been kept used on PSX and
+Nintendo DSi; those variants are just using the raw compression, without LArc
+archive headers.
+
+DSi Dr. Mario (DSiware, Nintendo/Arika, 2008-2009)
+ INFO.DAT
+ encrypted directory with filename, offset and compressed/uncompressed size
+ GAME.DAT
+ 000h 4 ID "ALZ1"
+ 004h ... ALZ1 Compressed data (with size as defined in INFO.DAT)
+ ... 4 ID "ALZ1"
+ ... ... ALZ1 Compressed data (with size as defined in INFO.DAT)
+ ...
+
+PSX Final Fantasy VII (FF7)
+ALZ1 compression is used in various folders (ENEMY*, STAGE*, STARTUP, MAGIC,
+FIELD, MINI, MOVIE, WORLD) with various filename extensions (.LZS .BSX .DAT
+.MIM .TIZ .PRE .BSZ .TXZ).
+ 000h 4 Compressed Size ;=Filesize-4
+ 004h .. ALZ1 Compressed data (Filesize-4 bytes)
+Detection can be more or less reliably done by checking [000h]=Filesize-4, one
+could also check the filename extensions, although .DAT doesn't qualify as
+unique extension.
+The file doesn't contain any info on the decompressed size, so one cannot know
+the decompression buffer size without first decompressing the file.
+Note: For whatever reason, the game does also have one GZIP compressed file
+(BATTLE\TITLE.BIN).
+
+PSX Final Fantasy VIII (FF8)
+About same as FF7, but detection is less reliable because there are no
+filenames or extensions, and the file header is somewhat randomly set to
+[000h]=(Filesize-4)+0..7, unknown why, maybe it's allocating dummy bytes to
+last some compression flags.
+ 000h 4 Compressed Size+0..7 ;=(Filesize-4)+0..7
+ 004h .. ALZ1 Compressed data (Filesize-4 bytes)
+ALZ1 is used in four Root files (0001h,0002h,0017h,001Ah), and in many Field
+files, and maybe in further files elsewhere.
+
+PSX Ultimate Fighting Championship (MagDemo38: UFC\CU00.RBB\383h\*)
+ 000h 8 ID "00zLATAD" (aka DATALz00 backwards) ;\PreHeader
+ 008h 4 Total Filesize excluding PreHeader+Padding (SIZ+0Ch) ;/
+ 00Ch 4 Unknown (always 1000h) ;\
+ 010h 4 Compressed data size (SIZ) ; Header
+ 014h 4 Decompressed data size ;/
+ 018h SIZ zLATAD Compressed data ;-Data
+ ... .. Padding to 4-byte boundary ;-Padding
+
+Ninja (MagDemo13: NINJA\LOADPICS\*.PAK and NINJA\VRW\FOREST.VRW\*)
+ 000h 8 ID "VRAM-WAD"
+ 008h 4 Compressed size (Filesize-Padding-10h)
+ 00Ch 4 Decompressed size (18000h, 28000h, 40000h bytes)
+ 010h .. VRAMWAD Compressed data (192x256, 320x256, 512x256 halfwords)
+ ... (..) Padding to 4-byte boundary (if any, in files in .VRW archives)
+Observe that Ninja is using the same ID="VRAM-WAD" for .PAK files and .VRW
+archives (if [008h]=Filesize-Padding-10h then it's a compressed .PAK file,
+otherwise it's a .VRW archive; whereas, those .VRW archives do themselves
+contain several .PAK files).
+
+PSX Power Spike (MagDemo43: POWER\GAME.IDX\*.BIZ)
+BIZ compression is used in BIZ archives (which are nested in IDX/HUG archive).
+The compressed & decompressed size is stored in the BIZ archive.
+Note: Power Spike 20h-filled initial BIZ ringbuf is required for sky pixels in:
+ MagDemo43: POWER\GAME.IDX\PERSOS\PSX\CUSTOM\\TEXTURE\NFIELD.BIZ\LPORJ.PSI
+
+PSX Army Men Air Attack 2 (MagDemo40: AMAA2\*.PCK\*.PAK)
+SCRATCH compression is used in PAK archives (which are nested in PCK archive).
+The compressed & decompressed size is stored in the PAK archive.
+Note: The decompressor uses half of the 1Kbyte Scratchpad RAM at 1F800000h as
+ringbuf (hence the name and unusual small 200h-byte ringbuf size).
+
+Alice in Cyberland (ALICE.PAC\*.FA2)
+ 000h .. FA2 Compressed .FA archive
+The decompressor is at 80093A3Ch (but the code isn't permanently in memory),
+and it's by far one of the worst decompression functions in compilerland.
+
+Decompression
+ DEFAULT = ALZ1 or BIZ or LZ5
+ if DEFAULT then wr=0FEEh, mask=FFFh ;\
+ if VRAMWAD then wr=0FEEh, mask=FFFh ; initial ringbuf write index
+ if zLATAD then wr=0000h, mask=FFFh ; and ringbuf mask (size-1)
+ if SCRATCH then wr=01BEh, mask=1FFh ;
+ if FA2 then wr=00EFh, mask=0FFh ;/
+ if FA2 then len2=0
+ initialize_ringbuf_content (see below)
+ numbits=0
+ @@decompress_lop:
+ if dst>=dst.end then goto @@decompress_done
+ if numbits=0
+ flagbits=[src], numbits=8, src=src+1 ;8bit flags
+ numbits=numbits-1
+ if VRAMWAD or FA2 then flagbits SHL 1, else flagbits=flagbits SHR 1
+ if carry=1 then
+ dta=[src], [dst]=dta, ringbuf[wr AND mask]=dta
+ dst=dst+1, wr=wr+1, src=src+1
+ else
+ if DEFAULT then rd=[src]+([src+1]/10h)*100h), len=([src+1] AND 0Fh)+3
+ if zLATAD then rd=[src]+([src+1] AND 0Fh)*100h), len=([src+1]/10h)+3
+ if SCRATCH then rd=[src]+([src+1]/80h)*100h), len=([src+1] AND 7Fh)+3
+ if VRAMWAD then rd=[src+1]+([src]/10h)*100h), len=([src] AND 0Fh)+3
+ if FA2 then rd=[src], len=len2, len2=0, src=src+1
+ if FA2 and len=0 then len=[src]/10h+2, len2=([src] AND 0Fh)+2, src=src+1
+ if FA2=0 then src=src+2
+ for i=1 to len ;read ringbuf[rd] (instead of relative [dst-rd])
+ dta=ringbuf[rd AND mask], [dst]=dta, ringbuf[wr AND mask]=dta
+ dst=dst+1, wr=wr+1, rd=rd+1
+ next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+Initial Ringbuf Content
+ if ALZ1 or zLATAD then
+ ringbuf[000h..FFFh]=(00h) ;zeroes
+ if VRAMWAD then
+ ringbuf[000h..FEDh]=(00h) ;zeroes
+ ringbuf[FEEh..FFFh]=(uninitialized) ;uninitialized, don't use
+ if BIZ then
+ ringbuf[000h..FEDh]=(20h) ;ascii space
+ ringbuf[FEEh..FFFh]=(uninitialized) ;uninitialized, don't use
+ if SCRATCH then
+ ringbuf[000h..1BFh]=(00h) ;zeroes
+ ringbuf[1C0h..1FFh]=(uninitialized) ;uninitialized, don't use
+ if FA2 then
+ ringbuf[000h..0FFh]=(00h) ;zeroes
+ if LZ5 then
+ ringbuf[000h..CFFh]=(000h..CFFh)/0Dh ;increasing, repeated 0Dh times each
+ ringbuf[D00h..DFFh]=(00h..FFh) ;increasing
+ ringbuf[E00h..EFFh]=(FFh..00h) ;decreasing
+ ringbuf[F00h..F7Fh]=(00h) ;zeroes
+ ringbuf[F80h..FEDh]=(20h) ;ascii space
+ ringbuf[FEEh..FFFh]=(should be 00h) ;see note, better don't use
+Note: The last 12h bytes in LZ5 are 00h in LArc v3.33 (though unknown if that's
+intended and stable), LHarc source code did accidentally set them to 20h (which
+is reportedly fixed in later LHA versions).
+
+CDROM File Compression PCK (Destruction Derby Raw)
+--------------------------------------------------
+
+Destruction Derby Raw (MagDemo35: DDRAW\*.PCK,EXE,DAT)
+ 000h 3 Decompressed size (24bit, little-endian)
+ 003h 1 Unused (0)
+ 004h ... LZSS compressed data, starting with 30bit+2bit flags
+The compression is used in some ISO files, which can be detected as:
+ [03h]=00h, [04h]=00h, [08h]="PS-X EXE" ;DDRAW\*.EXE
+ [03h]=00h, [04h] AND FCh=00h, [08h]="BC",04h,40h,0,0 ;DDRAW\LDPICS\*.PCK
+The compression is also used in nested PTH+DAT archives (where the whole DAT is
+compressed), which can be detected by checking if the sum of the PTH filesizes
+exceeds the DAT filesize.
+
+Decompression function
+ dst_end=dst+LittleEndian24bit[src], src=src+4
+ @@collect_more:
+ flagbits=BigEndian32bit([src]), src=src+4
+ dispbits=14-(flagbits AND 03h), flagbits=(flagbits OR 3)-1
+ dispmask=(1 SHL dispbits)-1
+ @@decompress_lop:
+ flagbits=flagbits SHL 1 ;32bit shift with carry-out/zeroflag
+ if zero then goto @@collect_more
+ if carry=0 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ disp=BigEndian16bit[src], src=src+2
+ len=(disp SHR dispbits)+3
+ disp=(disp AND dispmask)+1
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ id dst<dst_end then goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+CDROM File Compression GT-ZIP (Gran Turismo 1 and 2)
+----------------------------------------------------
+
+BS iki Video
+IKI is a rather uncommon variant of the .STR video format (used by Gran Turismo
+1 and 2, Legend of Legaia, Legend of Dragoon, Omega Boost, Um Jammer Lammy).
+IKI videos have a custom .BS header, including some GT-ZIP compressed data:
+ 000h 2 MDEC Size/4 (after huffman decompression) (rounded to 80h/4 bytes)
+ 002h 2 File ID (3800h)
+ 004h 2 Bitmap Width in pixels ;instead quant
+ 006h 2 Bitmap Height in pixels ;instead version
+ 008h 2 Size of GT-ZIP compressed data (plus 2-byte alignment padding)
+ 00Ah .. GT-ZIP compressed DC/Quant values (plus 2-byte alignment padding)
+ ... .. Huffman compressed AC data blocks (Cr,Cb,Y1,Y2,Y3,Y4, Cr,Cb,Y1,Y2..)
+The number of blocks is NumBlocks=(Width+15)/16*(height+15)/16*6. The size of
+the decompressed GT-ZIP data is NumBlocks*2.
+
+Gran Turismo 1 (MagDemo10: GT\*.DAT) - headerless
+Gran Turismo 1 (MagDemo15: GT\*.DAT) - headerless
+ 000h .. Compressed Data (without header)
+This is used for compressing files inside of GT-ARC archives (or in one case,
+for compressing the whole GT-ARC archive). The GT-ARC directory contains
+additional compression info, see GT-ARC description for details.
+The file GT\GAMEFONT.DAT is also GT-ZIP compressed, but lacks any ID or info on
+decompressed size, and there are at least two GAMEFONT.DAT versions (in
+MagDemo10 va MagDemo15), both versions are 8000h byte when decompressed, and
+compressed data starts with 00,FF,FF,00,00,00,80,00,00,01,17,07.
+
+Gran Turismo 2 (MagDemo27: GT2\GT2.VOL\arcade\arc_other.tim\*) - with header
+ 000h 0Ch ID "@(#)GT-ZIP",0,0
+ 00Ch 4 Decompressed Size
+ 010h .. Compressed Data (unknown compressed size due to below padding)
+ ... .. Zeropadding to 4-byte boundary (when stored in DOT1 archives)
+This is used for compressing some files in one DOT1 archive (most other files
+in Gran Turismo 2 are using GZIP compression; with corrupted/zeropadded GZIP
+footers).
+
+Decompression function
+ if [src]="@(#)GT-ZIP",0,0 then dst.end=dst+[src+0Ch], src=src+10h
+ @@collect_more:
+ flagbits=[src]+100h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ if src>=src.end then goto @@decompress_done ;(when src.end is known)
+ if dst>=dst.end then goto @@decompress_done ;(when dst.end is known)
+ flagbits=flagbits SHR 1
+ if zero then goto @@collect_more
+ if carry=0 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ len=[src], src=src+1, disp=[src], src=src+1 ;len, disp
+ if disp>=80h then disp=(disp-80h)*100h+[src], src=src+1 ;longer disp
+ for i=1 to (len+3), [dst]=[dst-(disp+1)], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+Notes
+Depending on the source, only the compressed or decompressed size may be known:
+ Source Compressed Size Decompressed Size
+ Compressed GAMEFONT.DAT In ISO Filesystem Unknown (n/a)
+ Compressed GT-ARC In ISO Filesystem Unknown (n/a)
+ Files in GT-ARC In GT-ARC In GT-ARC
+ Files with GT-ZIP header Unknown (due to padding) In GT-ZIP
+ DC values in IKI videos Unknown (due to padding) From Width*Height
+Gran Turismo 1 has ID "@(#)GT-ZIP" (and "@(#)G.T-ZIPB" whatever that is) stored
+in Main RAM (though unknown if/which/any files do have those IDs).
+Gran Turismo 2 has ID "@(#)GT-ZIP" in "GT2\GT2.VOL\arcade\arc_other.tim\*",
+apart from that, it does mainly use GZIP compressed files.
+
+CDROM File Compression GT20 and PreGT20
+---------------------------------------
+
+GT20 Compressed Files
+Used by Rollcage (MagDemo19: ROLLCAGE\SPEED.IMG\*)
+Used by Rollcage Stage II (MagDemo31: ROLLCAGE\SPEED.IDX\*)
+Used by Sydney 2000 (MagDemo37: OLY2000\DEMO.IDX\* and OLY2000\GTO\*.GTO)
+Reportedly also Chill (PS1) (*.GTO)
+Reportedly also Ducati World: Racing Challenge
+Reportedly also Martian Gothic: Unification (PS1) (*.GT20)
+ 000h 4 ID ("GT20"=Compressed) (or reportedly "NOGT"=Uncompressed)
+ 004h 4 Size of decompressed data in bytes
+ 008h 4 Overlap for in-situ decompression (usually 3, or sometimes 7)
+ 00Ch 4 Size of Leading Zeropadding in bytes (0..7FFh)
+ 010h .. Leading Zeropadding (0..7FFh bytes)
+ ... .. Compressed Data
+The Leading Zeropadding can be used to arrange the data to end on a sector
+boundary (useful when loading the file in units of whole sectors, and wanting
+to load it to the end of the decompression buffer).
+ DecompressGT20:
+ src=src+word[src+0Ch]+10h ;skip header and any leading zeropadding
+ collected=00000001h ;end-bit
+ @@lop:
+ if GetBit=0
+ [dst]=[src], dst=dst+1, src=src+1 ;uncompressed byte
+ else
+ if GetBit=0
+ disp=byte[src]-100h, src=src+1 ;disp=(-100h..-1)
+ len=(GetBit*2)+(GetBit*1)+2 ;len=(2..5)
+ else
+ tmp=halfword[src], src=src+2
+ disp=(tmp/8)-2000h ;disp=(-2000h..-1)
+ len=(tmp AND 7)+2 ;len=(2..9)
+ if len=2
+ tmp=byte[src], src=src+1
+ if (tmp AND 80h) then disp=disp-2000h ;disp=(-4000h..-1)
+ len=(len AND 7Fh)+2 ;len=(2..81h)
+ if len=3 then goto decompression_done
+ if len=2 then len=halfword[src], src=src+2 ;len=(0..FFFFh)
+ for i=1 to len, [dst]=[dst+disp], dst=dst+1, next i
+ goto @@lop
+ ;---
+ GetBit:
+ collected=collected SHR 1
+ if zero then collected=(word[src] SHR 1)+80000000h, src=src+4
+ return carry (from shift right)
+Note: Uncompressed files can reportedly contain "NOGT" in the header, however,
+Rollcage does have compressed files (with GT20 header), and raw uncompressed
+files (without any NOGT header).
+See also: https://zenhax.com/viewtopic.php?t=13175 (specs)
+See also: http://wiki.xentax.com/index.php/GT20_Archive (blurp)
+
+Pre-GT20 Compressed Files
+Used by Bloody Roar 1 (MagDemo06: BL\*.DAT\*)
+Used by Bloody Roar 2 (MagDemo22: ASC,CMN,EFT,LON,SND,ST5,STU\*.DAT\*)
+ 000h 4 Compression Method (0=None, 2=Compressed, Other=Invalid)
+ 004h 4 Compressed Size (SIZ) (same as decompressed when method=0)
+ 008h 4 Decompressed Size
+ 00Ch SIZ Compressed Data
+ ... .. Garbagepadding to 4-byte boundary (in 4-byte aligned DAT files)
+This is apparently on older version of what was later called GT20. The PreGT20
+decompression works as so:
+ DecompressPreGT20:
+ src=src+0Ch ;skip header
+ collected=80h ;end-bit
+ @@lop:
+ if GetBit=1
+ [dst]=[src], dst=dst+1, src=src+1 ;uncompressed byte
+ else
+ if GetBit=0
+ len=(GetBit*2)+(GetBit*1)+2 ;len=(2..5)
+ disp=byte[src]-100h, src=src+1 ;disp=(-100h..-1)
+ else
+ tmp=bigendian_halfword[src], src=src+2
+ disp=(tmp/8)-2000h ;disp=(-2000h..-1)
+ len=(tmp AND 7)+2 ;len=(2..9)
+ if len=2
+ len=byte[src]+1, src=src+1 ;len=(1..100h)
+ if len=1 then goto decompression_done
+ for i=1 to len, [dst]=[dst+disp], dst=dst+1, next i
+ goto @@lop
+ ;---
+ GetBit:
+ collected=collected SHL 1 ;8bit shift
+ if zero then collected=(byte[src] SHL 1)+01h, src=src+1
+ return carry (from 8bit shift left)
+Note: Uncompressed files with Method=0 exist in Bloody Roar 2 (CMN\SEL01.DAT).
+Bloody Roar 1 (MagDemo06) has decompressor at 8016DD64h (method 0 and 2).
+Bloody Roar 2 (MagDemo22) has decompressor at 8015C8C0h (method 0 and 2).
+
+CDROM File Compression HornedLZ
+-------------------------------
+
+Used by Project Horned Owl (*.BIN\*) (and within self-decompressing EXE)
+
+HornedLZ Detection
+The easiest way to detect HornedLZ files is to check first 4 bytes:
+ B3 10 00 4F .. Compressed TIM with TIM Type=00h (4bpp without CLUT)
+ DB 10 00 3F .. Compressed TIM with TIM Type=08h,09h,etc.
+Alternately, one could check the Chunktype (in the parent archive):
+ Type=05h can be uncompressed .TXT or HornedLZ-compressed .TIM
+ (check if 2nd data byte is ASCII or 10h)
+ Type=0Fh is a DOT1 archive with HornedLZ-compressed .TIMs
+ (parse the DOT1 archive and treat its contents as compressed .TIMs)
+ Type=10h contains Deflated TIMs
+ (a completely different compression method)
+
+DecompressHornedLZ:
+ collected=01h ;end-bit
+ @@lop:
+ if GetBit=1
+ [dst]=[src], dst=dst+1, src=src+1 ;uncompressed byte
+ else
+ if GetBit=1
+ tmp=[src], src=src+1
+ len=tmp/40h+2, disp=tmp or (-40h) ;len=(2..05h), disp=(-40h..-1)
+ else
+ tmp=[src]*100h+[src+1], src=src+2
+ len=tmp/1000h+2, disp=tmp or (-1000h) ;len=(2..11h), disp=(-1000h..-1)
+ if len=2 then
+ len=[src]+2, src=src+1 ;len=(2..101h)
+ if len=2 then goto decompression_done
+ for i=1 to len, [dst]=[dst+disp], dst=dst+1, next i
+ goto @@lop
+ ;---
+ GetBit:
+ collected=collected SHR 1
+ if zero then collected=([src] SHR 1)+80h, src=src+1
+ return carry (from shift right)
+Note: The end code has all bits zero, except, disp is don't care (it's usually
+FFFh).
+
+CDROM File Compression LZS (Gundam Battle Assault 2)
+----------------------------------------------------
+
+Gundam Battle Assault 2 (DATA\*.PAC\*, with ID="lzs")
+ 000h 4 ID ("lzs",00h)
+ 004h 4 Zerofilled
+ 008h 4 Fixed (must be 1) (method/version?)
+ 00Ch 14h Zerofilled
+ 020h 2 Fixed (must be 3) (method/version?)
+ 022h 2 Offset to Compressed Data minus 20h (usually 38h-20h)
+ 024h 4 Decompressed Size
+ 028h 2 Flagsize (must be 08h, 10h, or 20h) (usually 20h=32bit)
+ 02Ah 2 Lensize (must be 02h..07h) (usually 05h=5bit)
+ 02Ch 4 Compressed Size (total filesize, including "lzs" header)
+ 030h 8 Name? (always "000000",00h,00h)
+ 038h .. Compressed data (usually at offset 38h)
+decompress_gundam_lzs:
+ dst_end = dst+littleendian32bit[src+24h]
+ flg_bits = littleendian16bit[src+28h] ;8,16,32
+ len_bits = littleendian16bit[src+2Ah] ;2..7
+ len_mask = (1 shl len_bits)-1 ;03h..7Fh
+ src=src+littleendian16bit[src+22h]+20h
+ collected_bits=0
+ @@collect_more:
+ for i=0 to flg_bits/8-1 ;read 8bit/16bit/32bit little-endian
+ collected_bits=collected_bits+([src] SHL (i*8)), src=src+1
+ num_collected=flg_bits
+ @@decompress_lop:
+ if dst=dst_end then goto @@decompress_done
+ if num_collected=0 then goto @@collect_more
+ num_collected=num_collected-1
+ flagbits=flagbits SHR 1
+ if carry=1 then
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ temp=bigendian16bit[src], src=src+2
+ len=(temp AND len_mask)+3
+ disp=(temp SHR len_bits), if disp=0 then goto @@decompress_error
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+CDROM File Compression BZZ
+--------------------------
+
+Used in .BZZ archives. Note that there are three slightly different .BZZ
+archive formats (they are all using the same BZZ compression, only the BZZ
+archive headers are different).
+ Jersey Devil .BZZ (MagDemo10: JD\*.BZZ)
+ Bugs Bunny: Lost in Time (MagDemo25: BBLIT\*.BZZ)
+ The Grinch (MagDemo40: GRINCH\*.BZZ)
+Neither the file header nor the archive directory entries do contain any
+information about the decompressed size. Best workaround might be to decompress
+the file twice (without storing the output in 1st pass, to determine the size
+of the decompression buffer for 2nd pass).
+
+BZZ Decompression
+The compression is fairly standard LZSS, except that it supports non-linear
+length values, and it does support uncommon Len/Disp pairs like
+7bitLen/9bitDisp (though usually, it does use standard 4bitLen/12bitDisp).
+ decompress_bzz:
+ method=byte[src], src=src+1 ;method (00h..1Fh) ;usually/always 0Bh)
+ shifter = ((method/8) and 3) ;00h..03h ;usually 1
+ len_bits = ((method and 7) xor 7) ;07h..00h ;usually 4
+ len_mask = (1 shl len_bits)-1 ;7Fh..00h ;usually 0Fh
+ threshold=len_mask/2, if threshold>07h then threshold=13h ;usually 07h
+ for i=0 to len_mask
+ if i>threshold then len_table[i] = ((i-threshold) shl shifter)+threshold+3
+ else len_table[i] = i+3 ;method=18h max=(7Fh-13h)*8+13h+3=376h=886 decimal
+ next i ;method=0Hh max=(0Fh-07h)*2+07h+3=1Ah=26 decimal
+ num_flags=bigendian24bit[src]+1, src=src+3 ;NUM24+1
+ @@collect_more:
+ if src>=src_end then goto @@decompress_error
+ flagbits=[src]+100h, src=src+1 ;8bit flags
+ @@decompress_lop:
+ flagbits=flagbits SHR 1
+ if zero then goto @@collect_more
+ if carry=1 then
+ if src>=src_end then goto @@decompress_error
+ [dst]=[src], dst=dst+1, src=src+1
+ else
+ if src+1>=src_end then goto @@decompress_error
+ temp=bigendian16bit[src], src=src+2
+ len=len_table[temp AND len_mask]
+ disp=temp SHR len_bits, if disp=0 then goto @@decompress_error
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ endif
+ num_flags=num_flags-1, if num_flags>0 then goto @@decompress_lop
+ @@decompress_error:
+ ret
+Bug: Files can randomly contain NUM24 or NUM24+1 codes (that seems to be due to
+a compressor bug or different compressor versions; the two variants are
+unfortunately randomly mixed even within the same game).
+And, compressed files are padded to 4-byte boundary (making it impossible to
+distinguish between "NUM24+1" and "NUM24+padding").
+ Case 1) source has NUM24+1 codes
+ --> decode all NUM24+1 codes (otherwise output will be too small)
+ Case 2) source has NUM24 codes (and enough padding for another code)
+ --> decode all NUM24+1 codes (for compatibility with case 1)
+ --> output will have some constant garbage byte(s) appended
+ --> exception: omit last code if it contains invalid disp=0
+ Case 3) source has NUM24 codes (and not enough padding for another code)
+ --> decode only NUM24 codes (abort if NUM24+1 exceeds src_end)
+ --> output should (probably) have correct size
+ --> never exceed src_end which would be highly unstable
+
+CDROM File Compression RESOURCE (Star Wars Rebel Assault 2)
+-----------------------------------------------------------
+
+Star Wars Rebel Assault 2 (RESOURCE.*\*)
+BallBlazer Champions (*.DAT)
+ decompression function:
+ base=src, method=[src], dst_end=dst+BigEndian24bit[src+1], src=src+4
+ @@decompress_lop:
+ if dst>=dst_end then goto @@decompress_done
+ if [src] AND 80h then
+ if method=01h then
+ len=([src]-80h)/8+3, disp=(BigEndian16bit[src] AND 7FFh)+1, src=src+2
+ else ;method=02h
+ len=([src]-80h)+4, disp=(BigEndian16bit[src+1])+1, src=src+3
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1
+ else ;uncompressed
+ len=[src]+1, src=src+1
+ for i=1 to len, [dst]=[src], src=src+1, dst=dst+1
+ goto @@decompress_lop
+ @@decompress_done:
+ src=(src+3) AND NOT 3
+ if LittleEndian32bit[src]<>crc(base, src-base) then error
+ ret
+Note: Compression is (normally) used only in Top-level RESOURCE.* and *.DAT
+archives (not in Nested archives). The Top-level archives do also contain some
+uncompressed files (which contain data that is compressed on its own: SPU-ADPCM
+audio, or encrypted BS bitmaps).
+
+Special case for BallBlazer Champions
+Normally only Top-level archives contain compression, however, there are also
+some Nested archives with compression in BallBlazer Champions:
+ STD_BBX.DAT\s*t\tp_a\* ;\double compression, Top-level is ALSO compressed
+ BBX_INTR.DAT\data1\pics\* ;/
+ BBX_INTR.DAT\Stad\pics\* ;\
+ BBX_INTR.DAT\Stad\wire\* ; Nested archives with compression
+ BBX_INTR.DAT\Subtitl\* ;
+ BBX_INTR.DAT\Subtitl\sub\*;/
+The Nested archives don't have any compression flag or decompressed size
+entries (so there's no good way for detecting compression in nested files).
+
+CDROM File Compression TIM-RLE4/RLE8
+------------------------------------
+
+Ape Escape (Sony 1999) (MagDemo22: KIDZ\*) has several compressed and
+uncompressed TIMs in headerless archives, the archives can contain:
+ Compressed 4bpp RLE4-TIM with uncompressed CLUT ;\only 4bpp can be compressed
+ Compressed 4bpp RLE8-TIM with uncompressed CLUT ;/
+ Uncompressed 4bpp TIM with uncompressed CLUT ;\only this type/combinations
+ Uncompressed 8bpp TIM with uncompressed CLUT ; are allowed if uncompressed
+ Uncompressed 16pp TIM without CLUT ;/
+ End code 00000000h (plus more zeropadding) ;-end of headerless archive
+The compression method is indicated by changing a reserved halfword in the TIM
+header:
+ hdr[02h]=Method (0000h=Uncompressed, 0001h=RLE4, 0002h=RLE8)
+The rest of the bytes in TIM header and in CLUT section are same as for normal
+TIMs. The Bitmap section is as follows:
+Decompressed size must be computed as Width*Height*2. The Section Size entry
+contains Section header size, plus compressed size, plus padding to 4-byte
+boundary.
+Method=0001h (RLE4):
+ @@decompress_lop:
+ color=[src]/10h, len=([src] AND 0Fh)+1, src=src+1
+ for i=1 to len, putpixel(color), next i ;len=1..10h
+ if numpixels<Width*Height*4 then goto @@decompress_lop
+Method=0002h (RLE8):
+ @@decompress_lop:
+ color1=[src]/10h, color2=[src] AND 0Fh, src=src+1
+ if color1=color2
+ len=[src]+2, src=src+1
+ for i=1 to len, putpixel(color1), next i ;len=2..101h
+ else
+ putpixel(color1), if numpixels<Width*Height*4 then putpixel(color2)
+ for i=1 to len, putpixel(color) ;len=1..10h
+ if numpixels<Width*Height*4 then goto @@decompress_lop
+The decompression functions in Ape Escape (MagDemo22: KIDZ\*) are found at:
+ 80078760h ape_escape_load_tim_archive
+ 8007894Ch ape_escape_decompress_with_4bit_lengths
+ 800789FCh ape_escape_decompress_with_8bit_lengths
+Examples for compressed TIMs are found at:
+ RLE8: Ape Escape, MagDemo22: KIDZ\KKIIDDZZ.HED\DAT\file004h\1stTIM
+ RLE4: Ape Escape, MagDemo22: KIDZ\KKIIDDZZ.HED\DAT\file135h\1stTIM
+ RLE8: Ape Escape, MagDemo22: KIDZ\KKIIDDZZ.HED\DAT\file139h\1stTIM
+Being made by Sony, this might be an official (but late) TIM format extension,
+unknown if there are any other games using that compression.
+
+CDROM File Compression RLE_16
+-----------------------------
+
+Apocalypse (MagDemo16: APOC\CD.HED\*.RLE)
+Spider-Man (MagDemo31,40: SPIDEY\CD.HED\*.RLE)
+Spider-Man 2 (MagDemo50: HARNESS\CD.HED\*.RLE)
+ 000h 8 ID "_RLE_16_"
+ 008h 4 Decompressed Size (usually 3C008h) (33408h=Apocalypse warning.rle)
+ 00Ch .. RLE Compressed Data (usually a .BMR bitmap)
+This is using simple RLE compression with 16bit len/data units (suitable for
+16bpp VRAM data). The compression ratio ranges from not so bad to very bad.
+
+Decompression
+ src=src+0Ch ;skip ID and size
+ @@decompress_lop:
+ len=halfword[src], src=src+2
+ if len=0000h then goto @@decompress_done ;end-code
+ if (len AND 8000h)=0 then
+ for i=1 to len, halfword[dst]=halfword[src], dst=dst+2, src=src+2, next i
+ else
+ fillvalue=halfword[src], src=src+2
+ for i=1 to len-8000h, halfword[dst]=fillvalue, dst=dst+2, next i
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+Other RLE16 variants
+A similar RLE16 variant is used in Croc 1, and another variant in Croc 2.
+--> CDROM File Archive Croc 1 (DIR, WAD, etc.)
+--> CDROM File Archive Croc 2 (DIR, WAD, etc.)
+
+CDROM File Compression PIM/PRS (Legend of Mana)
+-----------------------------------------------
+
+Legend of Mana (.PIM/.PRS)
+ 000h 1 Unknown (always 01h) (maybe File ID or Compression method)
+ 001h .. Compressed data ;for TIM: usually 00,10, F0,00, 00,0x, F0,00, ...
+Compression codes are:
+ nn,data[nn+1] ;nn=00..EF len=nn+1 [dst]=data[1] ;-uncompressed
+ F0,xn len=n+3 [dst]=0x ;1x4bit ;\
+ F1,nn,xx len=nn+4 [dst]=xx ;1x8bit ;
+ F2,nn,yx len=nn+2 [dst]=0x,0y ;2x4bit ; RLE fill
+ F3,nn,xx,yy len=nn+2 [dst]=xx,yy ;2x8bit ;
+ F4,nn,xx,yy,zz len=nn+2 [dst]=xx,yy,zz ;3x8bit ;/
+ F5,nn,xx,data[nn+4] len=nn+4 [dst]=xx,data[1] ;\interleaved
+ F6,nn,xx,yy,data[nn+3] len=nn+3 [dst]=xx,yy,data[1] ; fill combo
+ F7,nn,xx,yy,zz,data[nn+2] len=nn+2 [dst]=xx,yy,zz,data[1] ;/
+ F8,nn,xx len=nn+4 [dst]=xx ;xx=xx+1 ;\
+ F9,nn,xx len=nn+4 [dst]=xx ;xx=xx-1 ; fill with
+ FA,nn,xx,ss len=nn+5 [dst]=xx ;xx=xx+ss ; signed step
+ FB,nn,xx,yy,ss ;ss=signed len=nn+3 [dst]=xx,yy ;yyxx=yyxx+ss ;/
+ FC,xx,ny len=n+4 [dst]=[dst-yxx-1] ;\
+ FD,xx,nn len=nn+14h [dst]=[dst-xx-1] ; LZ compress
+ FE,xn len=n+3 [dst]=[dst-x*8-8] ;/
+ FF len=0 end ;-end code
+The compression is used for several files in Legend of Mana:
+ BIN\*.BIN ---> packed misc binary
+ MAP\*\FDATA.PRS ---> packed resource, whatever
+ MAP\*\MAP*.PRS ---> packed MPD resource, "SKmapDat"
+ WM\WMTIM\*.PIM ---> packed TIM image, 384x384x4bpp, bad compression ratio
+ WM\WMAP\*.PAT ---> packed loaddata
+ WM\WMAP\*.PIM ---> packed TIM image, 320x256x16bit, with UNCOMPRESSED dupe
+
+CDROM File Compression BPE (Byte Pair Encoding)
+-----------------------------------------------
+
+Byte Pair Encoding (BPE) does replace the most common byte-pairs with bytes
+that don't occur in the data. That does work best if there are unused bytes
+(eg. ASCII text, or 8bpp bitmaps with less than 256 colors).
+
+Bust A Groove (MagDemo18: BUSTGR_A\*.BPE)
+Bust-A-Groove 2 (MagDemo37: BUSTAGR2\BUST2.BIN\*)
+ 000h 4 ID "BPE_"
+ 004h 4 Total Filesize of compressed file including header (big-endian)
+ ... .. Compression block(s)
+ Each compression block contains:
+ 000h .. Dictionary info
+ ... 2 Size of compressed data (big-endian)
+ ... .. Compressed data
+The decompression function in Bust A Groove (MagDemo18) is at 80023860h, the
+heap is in 1Kbyte Scratchpad RAM at 1F800208h, so heap size should be max 1F8h
+bytes (assuming that the remaining Scratchpad isn't used for something else).
+The fileheader lacks info about the decompressed size.
+
+Legend of Dragoon (MagDemo34: LOD\OVL\*.OV_ and LOD\SECT\*.BIN\*)
+ 000h 4 Decompressed size (little-endian)
+ 004h 4 ID "BPE",1Ah
+ 008h .. Compression block(s)
+ ... .. End code (00000000h) (aka last block with Blocksize=0)
+ Each compression block contains:
+ 000h 4 Size of decompressed block (little-endian) (or 0=End code)
+ 004h .. Dictionary info
+ ... .. Compressed data
+ ... .. Padding to 4-byte boundary
+Max nesting appears to be 2Ch, the decompression function allocates a 30h-byte
+heap on stack, and fetches source data in 32bit units (occupying 4 heap bytes),
+the decompressor does then remove 1 byte from heap, and adds 2 bytes in case of
+nested codes.
+
+BPE Decompression for Bust-A-Groove and Legend of Dragoon
+ if [src+0]="BPE_" then type=GROOVE ;\
+ if [src+4]="BPE",1Ah then type=DRAGOON ;
+ if type=GROOVE then src_end = src+BigEndian32bit[src+4] ; hdr
+ if type=DRAGOON then dst_end = dst+LittleEndian32bit[src+0] ;
+ src=src+8 ;/
+ @@block_lop:
+ if type=DRAGOON then ;\blk
+ dst_blk_end = dst+LittleEndian32bit[src]+4, src=src+4 ; len
+ if dst=dst_blk_end then goto @@decompress_done ;/
+ for i=00h to FFh, dict1[i]=i, next i ;\
+ i=00h ;
+ @@dict_lop: ; dict
+ num=[src], src=src+1 ;
+ if num>7Fh then i=i+(num-7Fh), num=0, if i=100h then goto @@dict_done ;
+ for j=0 to num ;
+ a=[src], src=src+1 ;
+ if a<>i then b=[src], src=src+1, dict1[i]=a, dict2[i]=a ;
+ i=i+1 ;
+ if i<100h then goto @@dict_lop ;
+ @@dict_done: ;/
+ if type=GROOVE then ;\blk
+ src_blk_end = src+BigEndian16bit[src]+2, src=src+2 ;/len
+ i=0 ;\
+ @@data_lop: ;
+ if i=0 then ;\ ; data
+ if type=GROOVE and src=src_blk_end then goto @@data_done ; get data ;
+ if type=DRAGOON and dst=dst_blk_end then goto @@data_done; from src ;
+ x=[src], src=src+1 ; or heap ;
+ else ; ;
+ i=i-1, x=heap[i] ;/ ;
+ a=dict1[x] ;-xlat ;
+ if a=x then ;\ ;
+ [dst]=x, dst=dst+1 ; output data to ;
+ else ; dst or heap ;
+ b=dict2[x], heap[i]=b, heap[i+1]=a, i=i+2 ;/ ;
+ goto @@data_lop ;
+ @@data_done: ;/
+ if type=GROOVE and src<src_end then goto @@block_lop ;\next
+ if type=DRAGOON then src=(src+3) AND not 3, goto @@block_lop ;/blk
+ @@decompress_done:
+ if type=DRAGOON and dst<>dst_end then error
+ ret
+
+Electronic Arts
+Electronic Arts games support several compression methods, including a BPE
+variant. That BPE variant is a bit unusual: It does have only one compression
+block (with a single dictionary for the whole file), and uses escape codes for
+rarely used bytes.
+--> CDROM File Compression EA Methods
+
+CDROM File Compression RNC (Rob Northen Compression)
+----------------------------------------------------
+
+Rob Northen compression
+Rob Northen compression (RNC) is a LZ/Huffman compression format used by
+various games for PC, Amiga, PSX, Mega Drive, Game Boy, SNES and Atari Lynx.
+Most RNC compressed files come in a standard 12h-byte header:
+ 000h 3 Signature ("RNC") (short for Rob Northen Computing compression)
+ 003h 1 Compression Method (01h or 02h)
+ 004h 4 Size of Uncompressed Data ;big-endian
+ 008h 4 Size of Compressed Data (SIZ) ;big-endian
+ 00Ch 2 CRC16 on Uncompressed Data (with initial value 0000h) ;big-endian
+ 00Eh 2 CRC16 on Compressed Data (with initial value 0000h) ;big-endian
+ 010h 1 Leeway (difference between compressed and uncompressed data in
+ largest pack chunk, if larger than decompressed data)
+ 011h 1 Number of pack chunks
+ 012h SIZ Compressed Data
+ ... (..) Zeropadding to 800h-byte boundary-4 ;\as so in PSX Heart of Darkness
+ ... (4) Unknown ;/
+The compressed data consists of interleaved bit- and byte-streams, the first 2
+bits of the bit stream are ignored.
+
+RNC Method 1 - with custom Huffman trees
+The bit-stream is read in 16bit units (the 1st bit being in bit0 of 1st byte).
+ Each pack chunk contains the following:
+ * 3 Huffman trees (one for literal data sizes, one for distance values,
+ and one for length values) in the bit stream. These consist of:
+ o A 5 bit value for the amount of leaf nodes in the tree
+ o 4 bit values for each node representing their bit depth.
+ * One 16 bit value in the bitstream for the amount of subchunks in the
+ pack chunk.
+ * The subchunk data, which contains for each subchunk:
+ o A Huffman code value from the first tree in the bit stream for the
+ amount of literals in the byte stream.
+ o Literals from the byte stream.
+ o A Huffman code from the bit stream that represents the distance - 1
+ of a distance/length pair.
+ o A Huffman code from the bit stream that represents the length - 2
+ of a distance/length pair.
+Unknown how that works exactly (see source code for details), unknown if method
+1 was used on PSX.
+
+RNC Method 2 - with hardcoded Huffman trees
+The bit-stream is read in 8bit units (the 1st bit being in bit7).
+ 0 + Byte(DATA[1]) Copy 1 Byte from Source
+ 1000 + Dist + Byte(X) Copy 4 Bytes from Dest-(Dist+X+1)
+ 10010 + Dist + Byte(X) Copy 6 Bytes from Dest-(Dist+X+1)
+ 10011 + Dist + Byte(X) Copy 7 Bytes from Dest-(Dist+X+1)
+ 1010 + Dist + Byte(X) Copy 5 Bytes from Dest-(Dist+X+1)
+ 10110 + Dist + Byte(X) Copy 8 Bytes from Dest-(Dist+X+1)
+ 10111 + nnnn + Byte(DATA[12..72]) Copy nnnn*4+12 Bytes from Source
+ 110 + Byte(X) Copy 2 Bytes from Dest-(X+1)
+ 1110 + Dist + Byte(X) Copy 3 bytes from Dest-(Dist+X+1)
+ 1111 + Byte(0) + 0 + zeropadding End of last pack chunk
+ 1111 + Byte(0) + 1 End of non-last pack chunk
+ 1111 + Byte(L) + Dist + Byte(X) Copy L+8 Bytes from Dest-(Dist+X+1) ;L>00h
+Dist values:
+ 0 = 0000h 1000 = 0200h
+ 110 = 0100h 1001 = 0300h
+ 111000 = 0C00h 101000 = 0800h
+ 111001 = 0D00h 101001 = 0900h
+ 11101 = 0600h 10101 = 0400h
+ 111100 = 0E00h 101100 = 0A00h
+ 111101 = 0F00h 101101 = 0B00h
+ 11111 = 0700h 10111 = 0500h
+The purpose of the pack chunks isn't quite clear, it might be related to memory
+restrictions on old CPUs. In PSX Heart of Darkness they are chosen so that the
+decompressed data is max 3000h bytes per chunk. Unknown if the next chunk may
+copy data from previous chunk.
+
+Links
+ http://aminet.net/package/util/pack/RNC_ProPack - official tool & source code
+ https://segaretro.org/Rob_Northen_compression - description (contains bugs)
+
+RNC is used in a number of games by UK developers (notably Bullfrog and
+Traveller's Tales), including Sonic 3D: Flickies' Island, Blam! Machinehead,
+Dungeon Keeper 2, Magic Carpet, Syndicate and Syndicate Wars.
+
+RNC in PSX Games
+ Method 2: Demolition Racer (MagDemo27: DR\DD.DAT\*.RNC)
+ Method 2: Heart of Darkness (IMAGES\US.TIM)
+ Method 2: Jonah Lomu Rugby (LOMUDEMO\GFX\*.PAK)
+ Method 2: NBA Jam: Tournament Edition (*.RNC, headerless .BIN/.GFX archives)
+ Method 2: Test Drive 5 (MagDemo13: TD5.DAT\*.RNC)
+ Method 2: Test Drive Off-Road 3 (MagDemo27: TDOR3\TDOR3.DAT\*.rnc)
+
+RNC in Mega Drive games
+ 3 Ninjas Kick Back
+ Addams Family
+ Addams Family Values
+ The Adventures of Mighty Max
+ Ast‚rix and the Great Rescue
+ Ast‚rix and the Power of the Gods
+ The Incredible Hulk
+ The Itchy & Scratchy Game (unreleased)
+ Marsupilami
+ Mortal Kombat
+ Mr. Nutz
+ Outlander
+ The Pagemaster
+ RoboCop 3
+ Spirou
+ Spot Goes to Hollywood
+ Stargate
+ Street Racer
+ Tinhead
+ Tintin in Tibet
+ World Championship Soccer II
+
+CDROM File Compression Darkworks
+--------------------------------
+
+Used by Alone in the Dark The New Nightmare (FAT.BIN\LEVELS\*\chunks)
+
+Decompression
+The decompressor is designed to hook the sector loading function: It does
+decompress incoming sectors during loading, and forwards the decompressed data
+to the original sector loading function. The decompressed data is temporarily
+stored in two small Dict buffers (which do also serve as compression
+dictionary).
+ decompress:
+ dictsize=1000h, dict0=alloc(dictsize), dict1=alloc(dictsize)
+ src=load_next_800h_byte_sector ;load first sector
+ dst=dict0 ;temp dest in current dict
+ dst_base=dst ;memorize start of newly decompressed data
+ @@decompress_lop:
+ if [src]=00h then ;\
+ esc=[src+1], src=src+1 ;
+ forward_to_actual_dest(source=dst_base, len=dst-dst_base) ; escape
+ if esc=0 or esc>4 then esc=2 (or warn_invalid_escape_code) ;
+ if esc=1 then goto @@decompress_done ;
+ if esc=2 or esc=4 then src=load_next_800h_byte_sector ;
+ if esc=3 or esc=4 then swap(dict0,dict1), dst=dict0 ;
+ dst_base=dst ;/
+ elseif ([src] AND 03h)=0 then ;\
+ len=[src]/4+2, dat=[src+1], src=src+2 ; fill 8bit
+ for i=1 to len, [dst]=dat, dst=dst+1 ;/
+ elseif ([src] AND 03h)=1 then ;\
+ len=[src]/4+([src+2] AND 40h)+4 ;
+ ptr=[src+1]+([src+2] AND 3Fh)*100h ; LZ compressed
+ if ptr+len>dictsize then error (exceeds allocated dictsize) ;
+ if ([src+2] AND 80h) then ptr=ptr=dict1 else ptr=ptr=dict0 ;
+ src=src+3 ;
+ for i=1 to len, [dst]=[ptr], ptr=ptr+1, dst=dst+1 ;/
+ elseif ([src] AND 03h)=2 then ;\
+ len=[src]/4+3, dat0=[src+1], dat1=[src+2], src=src+3 ; fill 16bit
+ for i=1 to len, [dst]=dat0, [dst+1]=dat1, dst=dst+2 ;/
+ elseif ([src] AND 03h)=3 then ;\
+ len=[src]/4+1, src=src+1 ; uncompressed
+ for i=1 to len, [dst]=[src], src=src+1, dst=dst+1 ;/
+ goto @@decompress_lop
+ @@decompress_done:
+ dealloc(dict0), dealloc(dict1)
+ ret
+There are one or more escape codes per sector (one to indicate the of the
+sector, plus further escape codes to swap the Dict buffers whenever the current
+Dict is full).
+The original decompressor is doing the forwarding in 800h-byte units, so Dict
+swapping may be only done when dict0 contains a multiple of 800h bytes (aka
+dictsize bytes).
+For whatever reason, there are only 4Kbyte per Dict allocated (although the
+14bit LZ indices could have addressed up to 16Kbyte per Dict).
+
+CDROM File Compression Blues
+----------------------------
+
+Blue's Clues: Blue's Big Musical (VRAM and FRAM chunks in *.TXD)
+Decompression function:
+ if LittleEndian32bit[src+08h]<>1 then error ;compression flag
+ dst_end=dst+LittleEndian32bit[src+14h], src=src+18h, num_collected=0
+ @@decompress_lop:
+ if GetBit=1 then
+ [dst]=[src], src=src+1, dst=dst+1 ;code 1 uncompressed byte
+ elseif GetBit=1 then
+ len=[src], src=src+1 ;code 01 fill or end code
+ if len=00h then goto @@decompress_done
+ len=len+1, fillvalue=[dst-1]
+ for i=1 to len, [dst]=fillvalue, dst=dst+1
+ else
+ len=GetBit*2+GetBit
+ if len=0 then ;code 0000 long LZ range
+ len=[src] AND 0Fh, disp=[src]/10h+[src+1]*10h-1000h, src=src+2
+ else ;code 00xx short LZ range
+ disp=[src]-100h, src=src+1
+ len=len+1
+ for i=1 to len, [dst]=[dst+disp], dst=dst+1
+ goto @@decompress_lop
+ @@decompress_done:
+ if dst<>dst_end then error
+ ret
+ ;---
+ GetBit:
+ if num_collected=0 then collected=[src], src=src+1, num_collected=8
+ collected=collected*2
+ return (collected/100h) AND 1
+
+CDROM File Compression Z (Running Wild)
+---------------------------------------
+
+Running Wild (MagDemo15: RUNWILD\*.BIN\*.Z and *.z)
+ decompress_z:
+ src=src+4 ;skip 32bit decompressed size entry
+ @@reload_lop:
+ load_table1 ;table for first 9bits
+ load_table2 ;table for codes longer than 9bits
+ @@decompress_lop:
+ sym=get_symbol()
+ if sym<100h then [dst]=sym, dst=dst+1, goto @@decompress_lop
+ if sym=100h then goto @@escape
+ len=sym-0FCh ;change 101h..140h to 05h..44h
+ disp=((get_symbol()-101h)*40h) ;change 101h..140h to 00h..3Fh*40h
+ disp=((get_symbol()-101h) or disp)+1 ;change 101h..140h to 00h..3Fh+above+1
+ copy len bytes from dst-disp to dst
+ goto @@decompress_lop
+ @@escape:
+ if GetBits(1)=0 then goto @@reload_lop
+ ret
+ ;-----
+ load_table1:
+ t=0
+ @@load_lop:
+ x=GetBits(10h)
+ if x and 8000h then num=1 else num=(1 shl (9-(x/400h)))
+ for i=1 to num, table1[t]=x, t=t+1, next i
+ if t<200h then goto @@load_lop
+ ret
+ ;-----
+ load_table2:
+ num=GetBits(9)*2 ;can be 0=none, max=3FEh
+ if num>0 then for i=0 to num-1, table2[i]=GetBits(9), next i
+ ret
+ ;-----
+ get_symbol:
+ ;returns a value in range 0..140h:
+ ; 00h..FFh = data 00h..FFh (or unused for disp codes)
+ ; 100h = escape (or unused for disp codes)
+ ; 101h..140h = length 05h..44h (or 6bit fraction of 12bit disp)
+ ; 141h..3FFh = would be possible for short codes, but shouldn't be used
+ x=table1[PeekBits(9)]
+ if (x and 8000h)=0 then SkipBits(x/400h), return (x and 3FFh) ;-short code
+ SkipBits(9) ;skip first 9 bits, and process futher bit(s).. ;\
+ x=x-0C000h ;change C000h..C1FFh and up to 000h..1FFh ; long code
+ @@lop: ; (with more
+ x=table2[x*2+GetBits(1)] ;branch node0/node1 ; than 9bit)
+ if x>=141h then x=x-141h, goto @@lop ;
+ return x ;/
+The bitstream is fetched in little endian 16bit units (the first bit is in bit7
+of second byte). PeekBits returns the next some bits without discarding them,
+SkipBits does discard them, GetBits does combine PeekBits+SkipBits.
+Note: The decompression function in Running Wild (MagDemo15) is at 80029D10h.
+
+CDROM File Compression ZAL (Z-Axis)
+-----------------------------------
+
+Thrasher: Skate and Destroy (MagDemo27: SKATE\ASSETS\*.ZAL) (Z-Axis)
+Dave Mirra Freestyle BMX (MagDemo36: BMX\ASSETS\*.ZAL) (Z-Axis)
+Dave Mirra Freestyle BMX (MagDemo46: BMX\ASSETS\*.ZAL) (Z-Axis)
+ZAL compression is used in ZAL archives. The archive header contains compressed
+and decompressed size for each file (and a compression flag indicating whether
+the archive is compressed at all).
+
+ZAL Decompression
+ if src_len=0 then goto @@decompress_done ;empty (without end code)
+ lzlen=0, rawlen=0
+ if [src]=10h..FFh then ;\special handling
+ rawlen=[src]-11h, src=src+1 ; for code=10h..FFh
+ if rawlen<=0 then goto @@decompress_error ;/at begin of source
+ @@decompress_lop:
+ memcopy(dst-disp,dst,lzlen) ;copy compressed bytes
+ memcopy(src,dst,rawlen) ;copy uncompressed bytes
+ code=[src], src=src+1
+ if code=00h..0Fh then
+ if rawlen=0 ;when OLD rawlen=0...
+ lzlen=0, rawlen=code+3 ;\
+ if rawlen=3 then ;
+ while [src]=00h, rawlen=rawlen+FFh, src=src+1 ;
+ rawlen=rawlen+[src]+0Fh, src=src+1 ;/
+ else ;when OLD rawlen>0, and depending on OLD lzlen...
+ rawlen=code AND 03h
+ disp=code/4+[src]*4, src=src+1
+ if lzlen=0 then disp=disp+801h, lzlen=3, else then disp=disp+1h, lzlen=2
+ if code=10h..1Fh then
+ lzlen=(code AND 07h)+2
+ if lzlen=2 then
+ while [src]=00h, lzlen=lzlen+FFh, src=src+1
+ lzlen=lzlen+[src]+07h, src=src+1
+ rawlen=[src] AND 03h, disp=[src]/4+[src+1]*40h+(code/8 AND 1)*4000h+4000h
+ src=src+2
+ if disp=4000h AND code=11h then goto @@decompress_done ;end code
+ if disp=4000h AND code<>11h then goto @@decompress_error
+ if code=20h..3Fh then
+ lzlen=code-20h+2
+ if lzlen=2 then
+ while [src]=00h, lzlen=lzlen+FFh, src=src+1
+ lzlen=lzlen+[src]+1Fh, src=src+1
+ rawlen=[src] AND 03h, disp=[src]/4+[src+1]*40h+1, src=src+2
+ if code=40h..FFh then
+ rawlen=code AND 03h
+ lzlen=(code/20h)+1
+ disp=((code/4) AND 07h)+([src]*8)+1, src=src+1
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+
+CDROM File Compression EA Methods
+---------------------------------
+
+Electronic Arts Compression Headers
+The files start with a 16bit big-endian Method value, with following bits:
+ 0-7 ID (usually FBh) (or 31h for Method 4A31h with 16bit sizes)
+ 8 Extended Header (usually 0) (or 1 for headers with extra entries)
+ 9-14 Used to distinguish different methods
+ 15 Extended Size (usually 0 for 24bit sizes) (or 1 for 32bit sizes)
+The most common Method values are:
+ 10FBh = LZSS Compression (RefPack)
+ 90FBh = LZSS Compression (RefPack, with 32bit size) (not on PSX)
+ 30FBh = Huffman Compression
+ 32FBh = Huffman Compression with filter
+ 34FBh = Huffman Compression with dual filter
+ 46FBh = BPE Byte-Pair Encoding
+ 4AFBh = RLE Run-Length Encoding
+ 4A31h = RLE Run-Length Encoding, with 16bit size
+ C0FBh = File Archive (not a compression method)
+Most or all PSX files have Bit8=0, but anyways, the decompressor does support
+skipping extra header entries in files with Bit8=1 (with all methods except
+RLE).
+Most or all PSX files have Bit15=0, games for newer consoles can reportedly
+have Method=90FBh (unknown if anything like B2FBh or CAFBh does also exist).
+Most or all PSX files have Bit0-7=FBh (supposedly short for Frank Barchard),
+the 16bit mode with Bit0-7=31h is supported for Method=4A31h only (the
+decompressor would also accept invalid methods like 1031h or 3431h, but doesn't
+actually support 16bit mode for those).
+
+Compression Formats
+--> CDROM File Compression EA Methods (LZSS RefPack)
+--> CDROM File Compression EA Methods (Huffman)
+--> CDROM File Compression EA Methods (BPE)
+--> CDROM File Compression EA Methods (RLE)
+
+Usage in PSX games
+The compression can be used to compress whole files:
+ PGA Tour 96, 97, 98 (*.* and *.VIV\*) (with method 10FBh)
+ Need for Speed 3 Hot Pursuit (*.Q* with method 10FBh, 30FBh, 32FBh)
+Or to compress texture bitmaps inside of .PSH file chunks:
+ FIFA - Road to World Cup 98 (*.PSH chunk C0h/C1h with method 10FBh)
+ Sled Storm (MagDemo24: ART3\LOAD*.PSH chunk C0h/C1h with method 10FBh)
+ WCW Mayhem (MagDemo28: WCWDEMO\*.BIG\*.PSH with chunk C0h/C1h with 10FBh)
+The decompressor supports further methods (like 34FBh, 46FBh, 4AFBh), but there
+aren't any files or chunks known to actually use those compression formats.
+
+Note: Some compressed files are slightly larger than uncompressed files (eg.
+filesizes for PGA Tour 96, 97, 98 COURSES\*\*.VIV\*.mis are compressed=58h,
+uncompressed=50h).
+
+See also
+http://wiki.niotso.org/RefPack - LZ method
+
+CDROM File Compression EA Methods (LZSS RefPack)
+------------------------------------------------
+
+RefPack
+ 000h 2 Method (10FBh, or 11FBh,90FBh,91FBh) (big-endian)
+ ... (3/4) Compressed size (24bit or 32bit) (optional)
+ ... 3/4 Uncompressed size (24bit or 32bit) (big-endoan)
+ ... .. Compressed data
+The compression is some kind of LZSS/LZH variant (similar to Z-Axis .ZAL
+files). The compressed data consists of a big-endian bit-stream (or
+byte-stream, as all codes are multiples of 8bits). The Compression codes are:
+ 0ddzzzrrdddddddd rawlen=r(2), lzlen=z(3)+3, disp=d(10)+1
+ 10zzzzzzrrdddddddddddddd rawlen=r(2), lzlen=z(6)+4, disp=d(14+1
+ 110dzzrrddddddddddddddddzzzzzzzz rawlen=r(2), lzlen=z(10)+5, disp=d(17)+1
+ 111rrrrr rawlen=r(5)*4+4, lzlen=0
+ 111111rr rawlen=r(2), lzlen=0, endflag=1
+refpack_decompress:
+ method=BigEndian16bit[src], src=src+2
+ if (method AND 100h)>0 then src=src+3+method/8000h ;compressed size, if any
+ if (method AND 8000h]=0 then dst_size=BigEndian24bit[src], src=src+3
+ if (method AND 8000h)>0 then dst_size=BigEndian32bit[src], src=src+4
+ endflag=0
+ @@decompress_lop:
+ if ([src] AND 80h)=0 then
+ rawlen=[src] AND 03h
+ lzlen=([src] AND 1Fh)/4+3
+ disp=([src] AND 60h)*8+[src+1]+1
+ src=src+2
+ elseif ([src] AND 40h)=0 then
+ rawlen=[src+1]/40h
+ lzlen=[src] AND 3Fh+4
+ disp=([src+1] AND 3Fh)*100h+[src+2]+1
+ src=src+3
+ elseif ([src] AND 20h)=0 then
+ rawlen=[src] AND 03h
+ lzlen=([src] AND 0Ch)*40h+[src+3]+5
+ disp=([src] AND 10h)*1000h+[src+1]*100h+[src+2]+1
+ src=src+4
+ elseif ([src] AND FCh)=FCh then
+ rawlen=[src] AND 03h
+ lzlen=0
+ src=src+1, endflag=1
+ else
+ rawlen=([src] AND 1Fh)*4+4
+ lzlen=0
+ src=src+1
+ for i=1 to rawlen, [dst]=[src], src=src+1, dst=dst+1, next i
+ for i=1 to lzlen, [dst]=[dst-disp], dst=dst+1, next i
+ if endflag=0 then goto @@decompress_lop
+ if (dst-dst_base)<>dst_size then error
+ ret
+
+CDROM File Compression EA Methods (Huffman)
+-------------------------------------------
+
+Huffman
+ 000h 2 Method (30FBh..35FBh) (big-endian)
+ ... (3) Extra 3 bytes (only present if Method.bit8=1)
+ ... 3 Decompressed Size (big-endian)
+ ... 1 Escape code
+ ... .. Number of codes per width
+ ... .. Data placement for each code
+ ... .. Compressed Data
+
+Huffman
+ decompress_ea_huffman:
+ method=GetBits(16) ;3xFBh ;-get method (30FBh..35FBh)
+ if method AND 100h then dummy=GetBits(24) ;-skip extra (if any)
+ dst_size=GetBits(24) ;-get uncompressed size
+ ESC=GetBits(8) ;-get escape code
+ huffwidth=0, huffcode=0, totalnumcodes=0 ;\
+ while (huffcode shl (10h-huffwidth))<10000h ;
+ num=GetVarLenCode ; get num codes per width
+ huffwidth=huffwidth+1 ;
+ numcodes_per_width[width]=num ;
+ totalnumcodes=totalnumcodes+num ;
+ huffcode=(huffcode*2)+num ;/
+ for i=0 to FFh, data_defined_flags[i]=00h ;\
+ dat=FFh, index=0 ;
+ while index<totalnumcodes ;
+ n=GetVarLenCode+1 ;- ; get/assign data values
+ while n>0 ;search Nth notyet defined entry ;
+ dat=(dat+1) AND FFh ;wrap in 8bit range! ;
+ if data_defined_flags[dat]=0 then n=n-1 ;
+ data_defined_flags[dat]=1 ;
+ data_values[index]=dat, index=index+1 ;/
+ huffcode=0000h, index=0 ;\
+ InitEmptyHuffTree(data_tree) ;
+ for width=1 to huffwidth ;
+ for i=1 to numcodes_per_width[width] ; create huffman tree
+ dat=data_values[index], index=index+1 ;
+ CreateHuffCode(data_tree,dat,huffcode,width) ;
+ huffcode=huffcode+(1 shl (10h-width) ;/
+ @@decompress_lop: ;\
+ dat=GetHuffCode(data_tree) ;
+ if dat<>ESC ;
+ [dst]=dat, dst=dst+1 ; decompress
+ else ;
+ num=GetVarLenCode ;
+ if num=0 then ;
+ if GetBits(1)=1 then goto @@decompress_done ;
+ [dst]=GetBits(8), dst=dst+1 ;
+ else ;
+ dat=[dst-1] ;
+ for i=0 to num-1, [dst]=dat, dst=dst+1 ;
+ goto @@decompress_lop ;/
+ @@decompress_done:
+ if (dst-dst_base)<>dst_size then error ;-error check
+ dst=dst_base, x=00h, y=00h ;\
+ if (method AND FEFFh)=32FBh ; optional final
+ for i=0 to dst_size-1, x=x+[dst+i], [dst+i]=x ; unfiltering
+ if (method AND FEFFh)=34FBh ;
+ for i=0 to dst_size-1, x=x+[dst+i], y=y+x, [dst+i]=y ;/
+ ret
+ ;------------------
+ GetVarLenCode:
+ num=2
+ while GetBits(1)=0, num=num+1
+ return (GetBits(num)+(1 shl num)-4)
+ GetBits(num):
+ return "num" bits, fetched from big-endian bitstream
+ GetHuffCode(data_tree):
+ ...
+ InitEmptyHuffTree(data_tree):
+ ...
+ CreateHuffCode(data_tree,dat,huffcode,width):
+ ...
+ numcodes_per_width[10h] ;9bit numcodes per width 0..15 (entry[0]=unused)
+ data_values[100h] ;8bit data values for up to 100h huffman codes
+ data_defined_flags[100h] ;1bit flags for data(00h..FFh)
+
+
+CDROM File Compression EA Methods (BPE)
+---------------------------------------
+
+Byte-Pair Encoding
+ 000h 2 Method (46FBh or 47FBh) (big-endian)
+ ... (5) Extra 5 bytes (only present if Method=47FBh)
+ ... 3 Decompressed Size (big-endian)
+ ... 1 Escape code
+ ... 1 Number of Dict entries (N)
+ ... N*3 Dict (each 3 bytes: Index,Dat1,Dat2)
+ ... .. Compressed Data
+decompress_bpe:
+ method=BigEndian16bit[src], src=src+2
+ if method=47FBh then src=src+5
+ dst_size=BigEndian24bit[src], src=src+3
+ esc=[src], src=src+1
+ num=[src], src=src+1
+ for i=0 to FFh, dict1[i]=i ;initially default=self (uncompressed bytes)
+ for i=1 to num, j=[src], dict1[j]=[src+1], dict2[j]=[src+2], src=src+3
+ @@decompress_lop:
+ x=[src], src=src+1
+ if x=dict1[x] then
+ if x=esc then x=[src], src=src+1, if x=00h then goto @@decompress_done
+ [dst]=x, dst=dst+1
+ else
+ heap[0]=x, i=1
+ while i>0
+ i=i-1, x=heap[i], a=dict1[x]
+ if a=x then [dst]=x, dst=dst+1 ;\output data to
+ else b=dict2[x], heap[i]=b, heap[i+1]=a, i=i+2 ;/dst or heap
+ goto @@decompress_lop
+ @@decompress_done:
+ if (dst-dst_base)<>dst_size then error
+ ret
+
+CDROM File Compression EA Methods (RLE)
+---------------------------------------
+
+Run-Length Encoding
+ 000h 2 Method (4AFBh=24bit or 4A31h=16bit) (big-endian)
+ ... 2/3 Decompressed Size (24bit or 16bit) (big-endian)
+ ... .. Compressed Data
+Compression codes are:
+ 00h..3Fh Copy 0..3Fh uncompressed bytes
+ 40h..7Fh Load new fillbyte and fill 0..3Fh bytes
+ 80h..BFh Use old fillbyte and fill 0..3Fh bytes (initial fillbyte=00h)
+ C0h..FFh Copy 0..3Fh bytes with constant value in upper 4bit
+decompress_bpe:
+ method=BigEndian16bit[src], src=src+2
+ if (method AND 00FFh)=31h then dst_size=BigEndian16bit[src], src=src+2
+ if (method AND 00FFh)<>31h then dst_size=BigEndian24bit[src], src=src+3
+ fillbyte=00h ;initially zero
+ @@decompress_lop:
+ type=[src]/40h, len=[src] AND 3Fh, src=src+1, dst_size=dst_size-len
+ if type=0 then ;\uncompressed bytes
+ for i=1 to len, [dst]=[src], src=src+1, dst=dst+1 ;/
+ elseif type=1 then ;\
+ fillbyte=[src], src=src+1 ; fill with new dat
+ for i=1 to len, [dst]=fillbyte, dst=dst+1 ;/
+ elseif type=2 then ;\fill with old dat
+ for i=1 to len, [dst]=fillbyte, dst=dst+1 ;/
+ elseif type=3 then
+ x=[src], [dst]=x, src=src+1, dst=dst+1, x=x AND F0h
+ for i=2 to len ;<-- or so?
+ if (i AND 1)=0 then [dst]=x+([src]/10h) dst=dst+1
+ if (i AND 1)=1 then [dst]=x+([src] AND 0Fh), dst=dst+1, src=src+1
+ if dst_size<>0 then goto @@decompress_lop
+ ret
+
+CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+------------------------------------------------------
+
+Inflate/Deflate is a common (de-)compression algorithm, used by ZIP, ZLIB, and
+GZIP.
+
+--> Inflate - Core Functions
+--> Inflate - Initialization & Tree Creation
+--> Inflate - Headers and Checksums
+
+In PSX cdrom-images, ZLIB is used by the .CDZ cdrom-image format:
+--> CDROM Disk Image/Containers CDZ
+In PSX games, ZLIB is used by:
+ Twisted Metal 4 (MagDemo30: TM4DATA\*.MR\* and *.IMG\*)
+ Kula Quest / Kula World / Roll Away (*.PAK) (*.PAK\*)
+ (and probably more games... particulary files starting with "x")
+In PSX games, GZIP is used by:
+ Final Fantasy VII (FF7) (BATTLE\TITLE.BIN)
+ Gran Turismo 2 (MagDemo27: GT2\*) (with corrupted/zeropadded GZIP footers)
+ Mat Hoffman's Pro BMX (old demo) (MagDemo39: BMX\BMXCD.HED\TITLE_H.ZLB)
+In PSX games, Inflate (with slightly customized block headers) is used by:
+ Mat Hoffman's Pro BMX (new demo) (MagDemo48: MHPB\FE.WAD+STR)
+In PSX games, Inflate (with ignored block type, dynamic tree only) is used by:
+ Project Horned Owl (COMDATA.BIN, DEMODATA.BIN, ROLL.BIN, ST*DATA.BIN)
+
+Inflate - Core Functions
+------------------------
+
+tinf_uncompress(dst,src)
+ tinf_init() ;init constants (needed to be done only once)
+ tinf_align_src_to_byte_boundary()
+ repeat
+ bfinal=tinf_getbit() ;read final block flag (1 bit)
+ btype=tinf_read_bits(2) ;read block type (2 bits)
+ if btype=0 then tinf_inflate_uncompressed_block()
+ if btype=1 then tinf_build_fixed_trees(), tinf_inflate_compressed_block()
+ if btype=2 then tinf_decode_dynamic_trees(), tinf_inflate_compressed_block()
+ if btype=3 then ERROR ;reserved
+ until bfinal=1
+ tinf_align_src_to_byte_boundary()
+ ret
+
+tinf_inflate_uncompressed_block()
+ tinf_align_src_to_byte_boundary()
+ len=LittleEndian16bit[src+0] ;get len
+ if LittleEndian16bit[src+2]<>(len XOR FFFFh) then ERROR ;verify inverse len
+ src=src+4 ;skip len values
+ for i=0 to len-1, [dst]=[src], dst=dst+1, src=src+1, next i ;copy block
+ ret
+
+tinf_inflate_compressed_block()
+ repeat
+ sym1=tinf_decode_symbol(tinf_len_tree)
+ if sym1<256
+ [dst]=sym1, dst=dst+1
+ if sym1>256
+ len = tinf_read_bits(length_bits[sym1-257])+length_base[sym1-257]
+ sym2 = tinf_decode_symbol(tinf_dist_tree)
+ dist = tinf_read_bits(dist_bits[sym2])+dist_base[sym2]
+ for i=0 to len-1, [dst]=[dst-dist], dst=dst+1, next i
+ until sym1=256
+ ret
+
+tinf_decode_symbol(tree)
+ sum=0, cur=0, len=0
+ repeat ;get more bits while code value is above sum
+ cur=cur*2 + tinf_getbit()
+ len=len+1
+ sum=sum+tree.table[len]
+ cur=cur-tree.table[len]
+ until cur<0
+ return tree.trans[sum+cur]
+
+tinf_read_bits(num) ;get N bits from source stream
+ val=0
+ for i=0 to num-1, val=val+(tinf_getbit() shl i), next i
+ return val
+
+tinf_getbit() ;get one bit from source stream
+ bit=tag AND 01h, tag=tag/2
+ if tag=00h then tag=[src], src=src+1, bit=tag AND 01h, tag=tag/2+80h
+ return bit
+
+tinf_align_src_to_byte_boundary()
+ tag=01h ;empty/end-bit (discard any bits, align src to byte-boundary)
+ ret
+
+Inflate - Initialization & Tree Creation
+----------------------------------------
+
+tinf_init()
+ tinf_build_bits_base(length_bits, length_base, 4, 3)
+ length_bits[28]=0, length_base[28]=258
+ tinf_build_bits_base(dist_bits, dist_base, 2, 1)
+ ret
+
+tinf_build_bits_base(bits,base,delta,base_val)
+ for i=0 to 29
+ bits[i]=min(0,i-delta)/delta
+ base[i]=base_val
+ base_val=base_val+(1 shl bits[i])
+ ret
+
+tinf_build_fixed_trees()
+ for i=0 to 6, tinf_len_tree.table[i]=0, next i ;[0..6]=0 ;len tree...
+ tinf_len_tree.table[7,8,9]=24,152,112 ;[7..9]=24,152,112
+ for i=0 to 23, tinf_len_tree.trans[i+0] =i+256, next i ;[0..23] =256..279
+ for i=0 to 143, tinf_len_tree.trans[i+24] =i+0, next i ;[24..167] =0..143
+ for i=0 to 7, tinf_len_tree.trans[i+168]=i+280, next i ;[168..175]=280..287
+ for i=0 to 111, tinf_len_tree.trans[i+176]=i+144, next i ;[176..287]=144..255
+ for i=0 to 4, tinf_dist_tree.table[i]=0, next i ;[0..4]=0,0,0,0,0 ;\dist
+ tinf_dist_tree.table[5]=32 ;[5]=32 ; tree
+ for i=0 to 31, tinf_dist_tree.trans[i]=i, next i ;[0..31]=0..31 ;/
+ ret
+
+tinf_decode_dynamic_trees()
+ hlit = tinf_read_bits(5)+257 ;get 5 bits HLIT (257-286)
+ hdist = tinf_read_bits(5)+1 ;get 5 bits HDIST (1-32)
+ hclen = tinf_read_bits(4)+4 ;get 4 bits HCLEN (4-19)
+ for i=0 to 18, lengths[i]=0, next i
+ for i=0 to hclen-1 ;read lengths for code length alphabet
+ lengths[clcidx[i]]=tinf_read_bits(3) ;get 3 bits code length (0-7)
+ tinf_build_tree(code_tree, lengths, 19) ;build code length tree
+ for num=0 to hlit+hdist-1 ;decode code lengths for dynamic trees
+ sym = tinf_decode_symbol(code_tree)
+ len=1, val=sym ;default (for sym=0..15)
+ if sym=16 then len=tinf_read_bits(2)+3, val=lengths[num-1] ;3..6 previous
+ if sym=17 then len=tinf_read_bits(3)+3, val=0 ;3..10 zeroes
+ if sym=18 then len=tinf_read_bits(7)+11, val=0 ;11..138 zeroes
+ for i=1 to len, lengths[num]=val, num=num+1, next i
+ tinf_build_tree(tinf_len_tree, 0, hlit) ;\build trees
+ tinf_build_tree(tinf_dist_tree, 0+hlit, hdist) ;/
+ ret
+
+tinf_build_tree(tree, first, num)
+ for i=0 to 15, tree.table[i]=0, next i ;clear code length count table
+ ;scan symbol lengths, and sum code length counts...
+ for i=0 to num-1, x=lengths[i+first], tree.table[x]=tree.table[x]+1, next i
+ tree.table[0]=0
+ sum=0 ;compute offset table for distribution sort
+ for i=0 to 15, offs[i]=sum, sum=sum+tree.table[i], next i
+ for i=0 to num-1 ;create code to symbol xlat table (symbols sorted by code)
+ x=lengths[i+first], if x<>0 then tree.trans[offs[x]]=i, offs[x]=offs[x]+1
+ next i
+ ret
+
+tinf_data
+ clcidx[0..18] = 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 ;constants
+
+ typedef struct TINF_TREE:
+ unsigned short table[16] ;table of code length counts
+ unsigned short trans[288] ;code to symbol translation table
+
+ TINF_TREE tinf_len_tree ;length/symbol tree
+ TINF_TREE tinf_dist_tree ;distance tree
+ TINF_TREE code_tree ;temporary tree (for generating the dynamic trees)
+ unsigned char lengths[288+32] ;temporary 288+32 x 8bit ;\for dynamic tree
+ unsigned short offs[16] ;temporary 16 x 16bit ;/creation
+
+ unsigned char length_bits[30]
+ unsigned short length_base[30]
+ unsigned char dist_bits[30]
+ unsigned short dist_base[30]
+
+Inflate - Headers and Checksums
+-------------------------------
+
+tinf_gzip_uncompress(dst, destLen, src, sourceLen)
+ src_start=src, dst_start=dst ;memorize start addresses
+ if (src[0]<>1fh or src[1]<>8Bh) then ERROR ;check id bytes
+ if (src[2]<>08h) then ERROR ;check method is deflate
+ flg=src[3] ;get flag byte
+ if (flg AND 0E0h) then ERROR ;verify reserved bits
+ src=src+10 ;skip base header
+ if (flg AND 04h) then src=src+2+LittleEndian16bit[src] ;skip extra data
+ if (flg AND 08h) then repeat, src=src+1, until [src-1]=00h ;skip file name
+ if (flg AND 10h) then repeat, src=src+1, until [src-1]=00h ;skip file comment
+ hcrc=(tinf_crc32(src_start, src-src_start) & 0000ffffh)) ;calc header crc
+ if (flg AND 02h) then x=LittleEndian16bit[src], src=src+2 ;get header crc
+ if (flg AND 02h) then if x<>hcrc then ERROR ;verify header
+ tinf_uncompress(dst, destLen, src, src_start+sourceLen-src-8) ;----> inflate
+ crc32=LittleEndian32bit[src], src=src+4 ;get crc32 of decompressed data
+ dlen=LittleEndian32bit[src], src=src+4 ;get decompressed length
+ if (dlen<>destLen) then ERROR ;verify dest len
+ if (crc32<>tinf_crc32(dst_start,dlen)) then ERROR ;verify crc32
+ ret
+
+tinf_zlib_uncompress(dst, destLen, src, sourceLen)
+ src_start=src, dst_start=dst ;memorize start addresses
+ hdr=BigEndian16bit[src], src=src+2 ;get header
+ if (hdr MOD 31)<>0 then ERROR ;check header checksum (modulo)
+ if (hdr AND 20h)>0 then ERROR ;check there is no preset dictionary
+ if (hdr AND 0F00h)<>0800h then ERROR ;check method is deflate
+ if (had AND 0F000h)>7000h then ERROR ;check window size is valid
+ tinf_uncompress(dst, destLen, src, sourceLen-6) ;------> inflate
+ chk=BigEndian32bit[src], src=src+4 ;get data checksum
+ if src-src_start<>sourceLen then ERROR ;verify src len
+ if dst-dst_start<>destLen then ERROR ;verify dst len
+ if a32<>tinf_adler32(dst_start,destLen)) then ERROR ;verify data checksum
+ ret
+
+tinf_adler32(src, length)
+ s1=1, s2=0
+ while (length>0)
+ k=max(length,5552) ;max length for avoiding 32bit overflow before mod
+ for i=0 to k-1, s1=s1+[src], s2=s2+s1, src=src+1, next i
+ s1=s1 mod 65521, s2=s2 mod 65521, length=length-k
+ return (s2*10000h+s1)
+
+
+CDROM File Compression LArc/LHarc/LHA (LZS/LZH)
+-----------------------------------------------
+
+LHA (formerly LHarc) is an old DOS compression tool with backwards
+compatibility for LArc. LHA appears to have been particulary popular in Japan,
+and in the Amiga scene.
+LHA archives are used by at least one PSX game:
+ PSX Championship Surfer (MagDemo43: HWX\*.DAT) ;method lh5
+And, there are various PSX games with compression based on LArc's method lz5:
+--> CDROM File Compression LZ5 and LZ5-variants
+
+Overall File Format
+Default archive filename extension is .LZH for LHarc/LHA (lh*-methods), or .LZS
+for LArc (lz*-methods).
+Archives can contain multiple files, and are usually terminated by a 00h-byte:
+ LHA Header+Data for 1st file
+ LHA Header+Data for 2nd file
+ End Marker (00h)
+There is no central directory, one must crawl all headers to create a list of
+files in the archive.
+Caution: There is a hacky test file (larc333\initial.lzs) with missing end byte
+(it does just end at filesize).
+LHA Header v2 Headersize=xx00h would conflict with End Byte (as workaround,
+insert a Nullbyte between Ext.Headers and Data to change Headersize to xx01h.
+
+LHA Header v0 (with [14h]=00h)
+ 00h 1 Header Size (Method up to including Extended Area) (=16h+F+E)
+ 01h 1 Header Checksum, sum of bytes at [02h+(0..15h+F+E)]
+ 02h 5 Compression Method (eg. "-lh0-"=Uncompressed)
+ 07h 4 Compressed Size
+ 0Bh 4 Uncompressed Size
+ 0Fh 2 Last modified time (in MS-DOS format)
+ 11h 2 Last modified date (in MS-DOS format)
+ 13h 1 MS-DOS File attribute (usually 20h)
+ 14h 1 Header level (must be 00h for v0)
+ 15h 1 Path\Filename Length
+ 16h (F) Path\Filename (eg. "PATH\FILENAME.EXT")
+ '\' may apper in the 2nd byte of Shift_JIS, processing
+ of Shift_JIS is indispensable when you need full
+ implementation of reading Pathname.
+ 16h+F 2 CRC16 (with initial value 0000h) on uncompressed file
+ 18h+F (E) Extended area (used by UNIX in v0)
+ 18h+F+E .. Compressed data
+Note: Reportedly, old LArc files don't have CRC16 (unknown if that is true, the
+ONLY known version is LArc v3.33, which DOES have CRC16, if older versions
+didn't have that CRC then they did perhaps behave as if E=(-2)?).
+
+LHA Header v1 (with [14h]=01h)
+ 00h 1 Header Size (Method up to including 1st Ext Size) (=19h+F+E)
+ 01h 1 Base Header Checksum, sum of bytes at [02h+(0..18h+F+E)]
+ 02h 5 Compression Method (eg. "-lh0-"=Uncompressed)
+ 07h 4 Skip size (size of all Extended Headers plus Uncompressed Size)
+ 0Bh 4 Uncompressed Size
+ 0Fh 2 Last modified time (in MS-DOS format)
+ 11h 2 Last modified date (in MS-DOS format)
+ 13h 1 Reserved (must be 20h) (but is 02h on Amiga)
+ 14h 1 Header level (must be 01h for v1)
+ 15h 1 Length of Filename (or 00h when name is in Extended Header)
+ 16h (F) Filename (eg. "FILENAME.EXT; path (if any) is in Extended Header)
+ 16h+F 2 CRC16 (with initial value 0000h) on uncompressed file
+ 18h+F 1 Compression Tool OS ID (eg. "M"=MSDOS)
+ 19h+F (E) Extended area (unused in v1, use Ext Headers instead)
+ 19h+F+E 2 Size of 1st Extended Header (0000h=None)
+ 1Bh+F+E .. Extended Header(s) (optional stuff)
+ ... .. Compressed data
+
+LHA Header v2 (with [14h]=02h)
+ 00h 2 Header Size (whole Header including all Extended Headers)
+ 02h 5 Compression Method (eg. "-lh0-"=Uncompressed)
+ 07h 4 Compressed Size
+ 0Bh 4 Uncompressed Size
+ 0Fh 4 Last modified date and time (seconds since 1st Jan 1970 UTC)
+ 13h 1 Reserved (must be 20h) (but is 02h on Amiga)
+ 14h 1 Header level (must be 02h for v2)
+ 15h 2 CRC16 (with initial value 0000h) on uncompressed file
+ 17h 1 Compression Tool OS ID (eg. "M"=MSDOS)
+ 18h 2 Size of first Extended Header (0000h=None)
+ 1Ah .. Extended Header(s) (filename and optional stuff)
+ ... 0/1 Nullbyte (End-Marker conflict: change Headersize xx00h to xx01h)
+ ... .. Compressed data
+
+LHA Header v3 (with [14h]=03h)
+Kinda non-standard (supported only in late japanese LHA beta versions): Allows
+Header and Ext.Headers to exceed 64Kbyte, which is rather useless.
+ 00h 2 Word size for 32bit Header entries (always 4=32bit)
+ 02h 5 Compression Method (eg. "-lh0-"=Uncompressed)
+ 07h 4 Compressed Size
+ 0Bh 4 Uncompressed Size
+ 0Fh 4 Last modified date and time (seconds since 1st Jan 1970 UTC)
+ 13h 1 Reserved (must be 20h)
+ 14h 1 Header level (must be 03h for v3)
+ 15h 2 CRC16 (with initial value 0000h) on uncompressed file
+ 17h 1 Compression Tool OS ID (eg. "M"=MSDOS)
+ 18h 4 Header Size (whole Header including all Extended Headers)
+ 1Ch 4 Size of first Extended Header (00000000h=None)
+ 20h .. Extended Header(s) (filename and optional stuff)
+ ... .. Compressed data
+
+Compression Methods
+ Method Len Window
+ -lz4- - - - LArc Uncompressed File
+ -lh0- - - - LHA Uncompressed File
+ -lhd- - - - LHA Uncompressed Directory name entry
+ -lzs- 2..17 2Kbyte LArc LZSS-Compressed (rare, very-very old) ;-15bit
+ -lz5- 3..17 4Kbyte LArc LZSS-Compressed (LArc srandard) ;-16bit
+ -lh1- 3..60 4Kbyte LHA LZHUF-Compressed (old LHA standard)
+ -lh2- 3..256 8Kbyte LHA Obscure test (used in self-extractor)
+ -lh3- 3..256 8Kbyte LHA Obscure test (experimental)
+ -lh4- 3..256 4Kbyte LHA AR002-Compressed (rare, for small RAM) ;\4bit
+ -lh5- 3..256 8Kbyte LHA AR002-Compressed (new LHA standard) ;/
+ -lh6- 3..256 32Kbyte LHA AR002-Compressed (rare) ;\
+ -lh7- 3..256 64Kbyte LHA AR002-Compressed (rare) ; 5bit
+ -lh8- 3..256 64Kbyte LHA AR002-Compressed (accidently same as lh7) ;
+ -lh9- 3..256 128Kbyte LHA AR002-Compressed (unimplemented proposal) ;
+ -lha- 3..256 256Kbyte LHA AR002-Compressed (unimplemented proposal) ;
+ -lhb- 3..256 512Kbyte LHA AR002-Compressed (unimplemented proposal) ;
+ -lhc- 3..256 1Mbyte LHA AR002-Compressed (unimplemented proposal) ;
+ -lhe- 3..256 2Mbyte LHA AR002-Compressed (unimplemented proposal) ;
+ -lhx- 3..256 512Kbyte LHA AR002-Compressed (rare) ;/
+Apart from above methods, there are various other custom hacks/extensions.
+
+Extended Headers
+ 00h 1 Extension Type (00h..FFh, eg. 01h=Filename)
+ 01h .. Extension Data
+ ... 2/4 Size of next Extended Header (0=None) (v1/v2=16bit, v3=32bit)
+Extension Type values:
+ 00h CRC16 on whole Header with InitialValue=0000h and InitialCrcEntry=0000h
+ 01h Filename
+ 02h Directory name (with FFh instead of "\", and usually with trailing FFh)
+ 3Fh Comment (unspecified format/purpose)
+ 40h MS-DOS File attribute of MS-DOS format
+ 41h Windows FILETIME for last access, creation, and modification
+ 42h Filesize (uncompressed and compressed size, when exceeding 32bit)
+ 50h Unix Permission
+ 51h Unix User ID and Group ID
+ 52h Unix Group name
+ 53h Unix User name (owner)
+ 54h Unix Last modified time in time_t format
+ 7Dh Capsule offs/size (if the OS adds extra header/footer to the filebody)
+ 7Eh OS/2 Extended attribute
+ 7Fh Level 3 Attribute in Unix form and MS-DOS form
+ FFh Level 3 Attribute in Unix form
+Note: There appears to be no MAC specific format (instead, the LHA MAC version
+is including a MacBinary header in the compressed files).
+
+See also
+The site below has useful links with info about headers (see LHA Notes), source
+code, and test archives:
+ http://fileformats.archiveteam.org/wiki/LHA
+
+CDROM File Compression ARJ
+--------------------------
+
+ARJ archives contain several chunks
+ Main header chunk
+ Local file chunk(s)
+ Chapter chunk(s), backup related, exist only in newer archives
+ End Marker
+
+ARJ main "comment" header, with [00Ah]=2
+This is stored at the begin of the archive. The format is same as for local
+file header (but with file-related entries set to zero, or to global security
+settings).
+ 000h 2 ARJ ID (EA60h, aka 60000 decimal)
+ 002h 2 Header size (from 004h up to including Filename+Comment) (max 2600)
+ 004h 1 Header size (from 004h up to including Extra Data) (1Eh+extra)
+ 005h 1 Archiver version number (01h..0xh)
+ 006h 1 Minimum archiver version to extract (usually 01h)
+ 007h 1 Host OS
+ 008h 1 ARJ Flags (bit0-7, see below)
+ 009h 1 Security version (2 = current)
+ 00Ah 1 File Type (must be 2=ARJ Comment in main header)
+ 00Bh 1 Reserved/Garbage (LSB of Archive creation Date/Time, same as [00Ch])
+ 00Ch 4 Date/Time when archive was created
+ 010h 4 Date/Time when archive was last modified
+ 014h 4 Zero (or Secured Archive size, excluding Security and Protection)
+ 018h 4 Zero (or Security envelope file position) (after End Marker)
+ 01Ch 2 Zero (or Filespec position in filename) (0) (what is that??)
+ 01Eh 2 Zero (or Security envelope size in bytes) (78h, if any)
+ 020h 1 Zero (or >2.50?: Encryption version, 0-1=Old, 2=New, 4=40bit GOST)
+ 021h 1 Zero (or >2.50?: Last chapter (eg. 4 when having chapter 1..4)
+ 022h (1) Extra data: ARJ Protection factor ;\extra,
+ 023h (1) Extra data: ARJ Flags (bit0=ALTVOLNAME, bit1=ReservedBit) ; if any
+ 024h (2) Extra data: Spare bytes ;/
+ ... .. Filename, max 500 bytes ("FILENAME.ARJ",00h)
+ ... .. Comment, max 2048 bytes ("ASCII Comment",00h)
+ ... 4 CRC32 on Header (from 004h up to including Comment)
+ ... 2 Size of 1st extended header (usually 0=none)
+ ... (0) Extended Header(s?) (usually none such)
+
+ARJ local file header, with [00Ah]=0,1,3,4
+This occurs at the begin of each file in the archive.
+ 000h 2 ARJ ID (EA60h, aka 60000 decimal)
+ 002h 2 Header size (from 004h up to including Filename+Comment) (max 2600)
+ 004h 1 Header size (from 004h up to including Extra Data) (1Eh+extra)
+ 005h 1 Archiver version number
+ 006h 1 Minimum archiver version to extract (usually 01h)
+ 007h 1 Host OS
+ 008h 1 ARJ Flags (bit0,2-5)
+ 009h 1 Method
+ 00Ah 1 File Type (0=Binary, 1=Text, 3=Directory Name, 4=Volume Name)
+ 00Bh 1 Reserved/Garbage (LSB of Archive update Date/Time?)
+ 00Ch 4 Date/Time modified
+ 010h 4 Filesize, compressed (max 7FFFFFFFh)
+ 014h 4 Filesize, uncompressed
+ 018h 4 CRC32 on uncompressed file data
+ 01Ch 2 Zero (or Filespec position in filename) (what is that??)
+ 01Eh 2 File access mode (aka MSDOS file attribute) (20h=Normal)
+ 020h 1 Zero (or >2.50?: first chapter of file's lifespan)
+ 021h 1 Zero (or >2.50?: last chapter of file's lifespan)
+ 022h (4) Extra data: Extended file position (maybe for split?) ;\extra,
+ 026h (4) Extra data: Date/Time accessed ;\ARJ ; 0,4 or 10h
+ 03Ah (4) Extra data: Date/Time created ; 2.62 ; bytes
+ 03Eh (4) Extra data: Original file size even for volumes ;/ ;/
+ ... .. Filename, max 500 bytes ("PATH/FILENAME.EXT",00h)
+ ... .. Comment, max 2048 bytes ("ASCII Comment",00h)
+ ... 4 CRC32 on Header (from 004h up to including Comment)
+ ... 2 Size of 1st extended header (usually 0=none)
+ ... (0) Extended Header(s?) (usually none such)
+ ... .. Compressed file data
+Entry 3Eh might be meant to contain Original Size of TEXT files (with CR,LFs),
+however, the entry is just set to 00000000h in ARJ 2.75a. Or maybe it's meant
+to mean size of whole file (in split-volumes)?
+
+ARJ backup "chapter" header (ARJ >2.50?) (exists in 2.75a), with [00Ah]=5
+This is rarely used and supported only in newer ARJ versions. The format is
+same as for local file header (but with file-related entries being nonsense in
+TECHNOTE; in practice, those nonsense values seem to be zero).
+ 000h 2 ARJ ID (EA60h, aka 60000 decimal)
+ 002h 2 Header size (from 004h up to including Filename+Comment) (max 2600)
+ 004h 1 Header size (from 004h up to including Extra Data) (1Eh+extra)
+ 005h 1 Archiver version number (eg. 0Ah=2.75a)
+ 006h 1 Minimum archiver version to extract (usually 01h)
+ 007h 1 Host OS
+ 008h 1 ARJ Flags (usually 00h)
+ 009h 1 Method (usually 01h, although chapters have no data) what file???
+ 00Ah 1 File Type (must be 5=ARJ Chapter)
+ 00Bh 1 Reserved/Garbage (LSB of Chapter Date/Time, same as [00Ch])
+ 00Ch 4 Date/Time stamp created
+ 010h 4 Zero (or reportedly, ?) what question?
+ 014h 4 Zero (or reportedly, ?) what question?
+ 018h 4 Zero (or reportedly, original file's CRC32) what file???
+ 01Ch 2 Zero (or reportedly, entryname position in filename) what file???
+ 01Eh 2 Zero (or reportedly, file access mode) what file???
+ 020h 1 Chapter range start (01h=First chapter?) what range???
+ 021h 1 Chapter range end (contains same value as above) what range???
+ 022h (4) Extra data: Extended file position (usually none such)what extra???
+ ... .. Filename ("<<<001>>>",00h for First chapter)
+ ... .. Comment ("",00h)
+ ... 4 CRC32 on Header (from 004h up to including Comment)
+ ... 2 Size of 1st extended header (usually 0=none)
+ ... (0) Extended Header(s?) (usually none such)
+
+ARJ End Marker (with [002h]=0000h)
+This is stored at the end of the archive.
+ 000h 2 ARJ ID (EA60h, aka 60000 decimal)
+ 002h 2 Header size (0=End)
+Note: The End Marker may be followed by PROTECT info and Security envelope.
+
+ARJ Method [009h]
+ 0 = stored (uncompressed)
+ 1 = compressed most (default) (Window=6800h=26Kbyte, Chars=255, Tree=31744)
+ 2 = compressed medium (Window=5000h=20Kbyte, Chars=72, Tree=30720)
+ 3 = compressed less (Window=2000h=8Kbyte, Chars=32, Tree=30720)
+ 4 = compressed least/fastest (Window=6800h? or 8000h?)
+ 8 = no data, no CRC ;\unknown if/where that is used (maybe only used
+ 9 = no data ;/internally, and never stored in actual files?)
+
+ARJ File Type [00Ah]
+ 0 = binary file (default)
+ 1 = text file (with converted line breaks, via -t1 switch)
+ 2 = ARJ comment header (aka ARJ main file header)
+ 3 = directory name
+ 4 = volume label (aka disc name)
+ 5 = ARJ chapter label (aka begin of newer backup sections)
+
+ARJ Flags (in Main [008h])
+ 0 GARBLED
+ 1 OLD_SECURED has old signature (with signature in Main Header?)
+ 1 ANSIPAGE ANSI codepage used by ARJ32 (for what? for "FILENAME.ARJ"?)
+ 2 VOLUME presence of succeeding volume
+ 3 ARJPROT
+ 4 PATHSYM archive name translated ("\" changed to "/")
+ 5 BACKUP obsolete
+ 6 SECURED has new signature (in security envelope?)
+ 7 ALTNAME dual-name archive
+ARJ Flags (in Local [008h])
+ 0 GARBLED passworded file
+ 1 NOT USED
+ 2 VOLUME continued file to next volume (file is split)
+ 3 EXTFILE file starting position field (for split files)
+ 4 PATHSYM filename translated ("\" changed to "/")
+ 5 BACKUP_FLAG obsolete
+ARJ Flags (in Chapter [008h])
+ 0 GARBLED ;\
+ 1 RESERVED ;
+ 2 VOLUME ; what does that mean in Chapters???
+ 3 EXTFILE ;
+ 4 PATHSYM ;/
+ 5 BACKUP obsolete < 2.50a ;-how can obsolete exist in Chapters???
+ 6 RESERVED
+
+Host OS [007h]
+ 0=MSDOS, 1=PRIMOS, 2=UNIX, 3=AMIGA, 4=MACDOS (aka MAC-OS)
+ 5=OS/2, 6=APPLE GS, 7=ATARI ST, 8=NEXT
+ 9=VAX VMS, 10=WIN95, 11=WIN32 (aka WinNT or so?)
+
+ARJ Method 1-3 (LHA/LZH compression)
+These methods are same as LHA's "-lh6-" compression method (albeit the three
+ARJ methods are allocating slighly less memory for the sliding window).
+
+ARJ Method 4 (custom fastest compression)
+ @@decompress_lop:
+ if dst>=dst_end then goto @@decompress_done
+ width=count_ones(max=7), len = get_bits(width) + (1 shl width)+1
+ if len=2 then
+ [dst]=get_bits(8), dst=dst+1
+ else ;len>=3
+ width=count_ones(max=4)+9, disp = get_bits(width) + (1 shl width)-1FFh
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+ ;---
+ count_ones(max):
+ num=0
+ @@lop:
+ if get_bits(1)=1 then
+ num=num+1, if num<max then goto @@lop
+ return num
+get_bits(N) is same as in method 1-3 (fetching N bits, MSB first, starting with
+bit7 of first byte).
+
+ARJ Glossary & Oddities
+BACKUPs seem to keep old files (instead overwrting them by newer files)
+CHAPTERs seems to be a new backup type (instead of [008h].Bit5=Backup flag).
+COMMENTS can be text... with ANSI.SYS style ANSI escape codes?
+DATE/TIME stamps seem to be MSDOS format (16bit date plus 16bit time)
+EXTENDED headers seem to be unused, somewhat inspired on LHA format but with
+CRC32 instead CRC16 (unknown if the "1st extended header" can be followed by
+2nd, 3rd, and further extended headers in LHA fashion) (bug: older ARJ versions
+are reportedly treating the extended CRC32 as 16bit value).
+GARBLED seems to refer to encrypted password protected archives.
+PROTECTED seems to mean Error Correction added in newer ARJ archives.
+SECURED seems to mean archive with signature from registered manufacturers.
+SPLIT aka VOLUMEs means large ARJ's stored in fragments on multiple disks.
+TEXT (aka [00Ah]=1 aka -t1 switch aka "C Text" aka "7-bit text") converts
+linebreaks from CR,LF to LF to save memory (the uncompressed size and
+uncompressed CRC32 entries refer to that converted LF format, not to the
+original CR,LF format; the official name "7-bit text" is nonsense: All
+characters are stored as 8bit values, not 7bit values).
+TIMEBOMB causes newer ARJ versions to refuse to work (and request the user to
+check for non-existing newer updates) (eg. ARJ 2.86 is no longer working, ARJ
+2.75a does still work without timebomb).
+
+See also
+The various ARJ versions include .TXT or .DOC files (notably, ARJ.TXT is user
+manual, TECHNOTE.TXT contains hints on the ARJ file format). There's also an
+open source version.
+
+CDROM File Compression ARC
+--------------------------
+
+ARC Archives
+ARC is an old DOS and CP/M compression tool from 1985-1990. ARC files contain
+chunks in following format:
+ 000h 1 Fixed ID (1Ah)
+ 001h 1 Compression Method (00h..1Fh)
+ 002h 13 Filename ("FILENAME.EXT",00h) (garbage-padded if shorter)
+ 00Fh 4 Filesize, compressed
+ 013h 4 File Timestamp in MSDOS format
+ 017h 2 CRC16 with initial value 0000h on uncompressed/decrypted file
+ 019h (4) Filesize, uncompressed ;<-- not present for Method=1
+ ... .. Compressed file data (size as stored in [00Fh])
+The chunksize depends on the Method:
+ Method 00h and 1Fh --> Chunksize=02h (archive/subdir end markers)
+ Method 01h --> Chunksize=19h+[0Fh] (old uncompressed ARC archives)
+ Others Methods --> Chunksize=1Dh+[0Fh] (normal case)
+Compression Methods (aka "header versions"):
+ 00h End-of-archive marker (1Ah,00h)
+ 01h ARC v? Uncompressed (with short 19h-byte header)
+ 02h ARC v? Uncompressed (with normal 1Dh-byte header)
+ 03h ARC v? Packed (RLE90) Used for small files
+ 04h ARC v? Squeezed (RLE90+Huffman) Based on CP/M Squeeze
+ 05h ARC v4.00 Crunched (OldRandomizedLZW) Derived from LZWCOM
+ 06h ARC v4.10 Crunched (RLE90+OldRandomizedLZW) Alike CP/M Crunch v1.x
+ 07h ARC vBeta? Crunched (RLE90+NewRandomizedLZW) Leaked beta version?
+ 08h ARC v5.00 Crunched (RLE90+ClearGap12bitLZW) Most common ARC method
+ 09h Inofficial Squashed (ClearGap13bitLZW) Used by PKARC/PKPAK
+ 0Ah ARC v7.xx Trimmed (RLE90+LZHUF) Based on LHArc lh1
+ 0Ah Inofficial Crushed (RLE90+LZW/LZMW?) PAK
+ 0Bh Inofficial Distilled (LZ77+Huffman) PAK v2.0
+ 14h-1Dh ARC v6.0 Used/reserved for Information items:
+ 14h Archive info
+ 15h Extended File info (maybe a prefix(?) for actual file entries?)
+ 16h OS-specific info
+ 1Eh-27h ARC v6.0 Used/reserved for Control items:
+ 1Eh ARC v6.00 Subdir (nested ARC-like format, created by the "z" option)
+ 1Fh ARC v6.00 End-of-subdir marker (1Ah,1Fh)
+ 48h Not used in ARC ;\Hyper archives start with 1Ah,48h or 1Ah,53h
+ 53h Not used in ARC ;/(an unrelated format that also starts with 1Ah)
+ 80h-xxh Not used in ARC ;-Spark archives (ARC-like, with extended headers)
+Information items use standard 1Dh-byte headers (with [002h]="",00h,
+[00Fh]=SizeOfAllItem(s), [019h]=Junk. The data part at offset 01Dh can contain
+one or more item(s) in following format:
+ 000h 2 Item size (LEN)
+ 002h 1 Item Subtype
+ 003h .. Item Data (LEN-3 bytes)
+Information item types as used by ARC 6.0:
+ Method=14h, Subtype=0 Archive description (eg. "Comment blah",00h)
+ Method=14h, Subtype=1 Archive creator program name (eg. "ARC 7.12 ...",00h)
+ Method=14h, Subtype=2 Archive modifier program name
+ Method=15h, Subtype=0 File description (eg. "Comment blah",00h)
+ Method=15h, Subtype=1 File long filename (if not MS-DOS "8.3" filename)
+ Method=15h, Subtype=2 File extended date-time info (reserved)
+ Method=15h, Subtype=3 File Icon (reserved)
+ Method=15h, Subtype=4 File attributes (see below) (eg. "RWHSN",00h)
+ Method=16h, Subtype=.. Operating system info (reserved)
+File attributes can contain following uppercase chars:
+ R=ReadAccess, W=WriteAccess, H=HiddenFile, 1=SystemFile, N=NetworkShareable
+
+Sub-directories
+Sub-directories are implemented as nested ARC files - about same as when
+storing the sub-directory files in SUBDIR.ARC, and including that SUBDIR.ARC
+file in the main archive with Method 02h. Except that:
+It's using Method 1Eh (instead Method 02h), with filename SUBDIR (instead
+SUBDIR.ARC), and with [019h]=Nonsense (instead uncompressed size), and the
+nested file ends with Method 1Fh (instead Method 00h).
+
+RLE90 (run-length compression with value 90h used as escape code)
+ARC does use raw RLE90 for small files (eg. 4-byte "aaaa"). ARC does also use
+RLE90 combined with other methods (perhaps because ARC wasn't very fast,
+compressing 100Kbytes could reportedly take several minutes; and without RLE90
+pre-compression it might have been yet slower).
+ 90h,00h Output 90h, but DON'T change prevbyte ;<-- ARC
+ 90h,00h Output 90h, and DO set prevbyte=90h ;<-- BinHex
+ 90h,00h Output 90h, and UNKNOWN what to do ;<-- StuffIt
+ 90h,01h..03h Output prevbyte 00h..02h times (this is not useful)
+ 90h,04h..FFh Output prevbyte 03h..FEh times (this does save memory)
+ xxh Output xxh, and memorize prevbyte=xxh
+ arc_decompress_rle90:
+ src_end = src+src_size
+ prevbyte = <initially undefined in ARC source code>
+ @@decompress_lop:
+ if src>=src_end then goto @@decompress_done
+ x=[src], src=src+1
+ if x<>90h then
+ [dst]=x, dst=dst+1, prevbyte=x ;output x, and memorize prevbyte=x
+ else ;x=90h
+ x=[src], src=src+1
+ if x=00h then
+ [dst]=90h, dst=dst+1 ;output 90h, but DO NOT change prevbyte
+ if BinHex then prevbyte=90h ;for BinHex, DO change prevbyte
+ else
+ for i=1 to x-1, [dst]=prevbyte, dst=dst+1, next i
+ goto @@decompress_lop
+RLE90 is used by ARC (and Spark and ArcFS), StuffIt, and BinHex (some of these
+may handle "prevbyte" differently; the handling in ARC is somewhat stupid as it
+cannot compress repeating 90h-bytes).
+
+Squeeze
+ 000h 2 Number of Tree entries (0..100h) (when 0, assume tree=FEFFh,FEFFh)
+ 002h N*4 Tree entries (16bit node0, 16bit node1)
+ ... .. Huffman bitstream (starting in bit0 of first byte)
+ ... .. Maybe supposedly padding to byte boundary?
+ The 16bit nodes are:
+ 0000h..00FFh Next Tree index
+ 0100h..FEFEh Invalid
+ FEFFh End of compressed data
+ FF00h..FFFFh Data values FFh..00h (these are somewhat inverted/reversed)
+ arc_decumpress_squeeze:
+ if [src]=0000h then tree=empty_tree, else tree=src+2 ;-start tree
+ InitBitstreamLsbFirst(src+2+[src]*4) ;-start bitstream
+ @@decompress_lop:
+ index=0000h ;\
+ while index<FEFFh ; huffman decode
+ index=[tree+index*4+GetBits(1)*2] ;/
+ if index>FEFFh then ;-check end code
+ [dst]=(index XOR FFh) AND FFh), dst=dst+1 ;-store data
+ goto @@decompress_lop
+ return
+ empty_tree dw FEFFh,FEFFh ;upen empty tree, ARC defines two 1bit END codes
+http://fileformats.archiveteam.org/wiki/Squeeze
+
+Randomized LZW
+ arc_decompress_randomized_lzw:
+ num_free=1000h, stack=empty, oldcode=-1
+ for i=0 to FFFh, lzw_parent[i]=EEEEh ;mark all codes as unused
+ for i=0 to FFh, create_code(FFFFh,i) ;codes for 00h..FFh with parent=none
+ @@decompress_lop:
+ if src>=src_end then goto @@decompress_done
+ code=GetBitsMsbFirst(12), i=code
+ if lzw_parent[i]=EEEEh then i=oldcode, push(oldbyte) ;-for KwKwK strings
+ while lzw_parent[i]<>FFFFh, push(lzw_data[i]), i=lzw_parent[i]
+ oldbyte=lzw_data[i], [dst]=oldbyte, dst=dst+1
+ if oldcode<>-1 then create_code(oldcode,oldbyte)
+ oldcode=code
+ while stack<>empty, [dst]=pop(), dst=dst+1
+ goto @@decompress_lop
+ @@decompress_done:
+ ret
+ ;---
+ create_code(parent,data):
+ if num_free=0 then goto @@no_further_codes, else num_free=num_free-1 ;-full
+ i=(parent+data) AND 0000FFFFh ;\
+ if method=7 then i=(i*3AE1h) AND FFFh ;new "fast" randomizer ;
+ else i=(sqr(i OR 800h)/40h) AND FFFh ;old "slow" randomizer ;
+ if lzw_parent[i]=EEEEh then goto @@found_free ; alloc
+ while lzw_sibling[i]>0000h, do i=lzw_sibling[i] ;find chain end ; code
+ e=i, i=(i+65h) AND FFFh ;memorize chain end & do some random skip ;
+ while lzw_parent[i]<>EEEEh, do i=(i+1) AND FFFh ;find a free code ;
+ lzw_sibling[e]=i ;weirdly, i=0 will make it behave as sibling=none ;
+ @@found_free: ;/
+ lzw_data[i]=data, lzw_parent[i]=parent, lzw_sibling[i]=0000h ;-apply
+ @@no_further_codes:
+ ret
+Codes are always 12bit (unlike normal LZW that often starts with 9bit codes).
+There won't be any new codes created if the table is full, the existing codes
+can be kept used if they do match the remaining data (unfortunatly this LZW
+variant has no Clear code for resetting the table when they don't match).
+Instead of just using the first free entry, code allocation is using some weird
+pseudo-random-sibling logic (which is totally useless and will slowdown
+decompression, but compressed files do contain such randomized codes, so it
+must be reproduced here).
+
+ClearGap LZW
+This is more straight non-randomized LZW with Clear codes (and weird gaps after
+Clear codes). The compression (and gaps) are same as for nCompress (apart from
+different headers):
+--> CDROM File Compression nCompress.Z
+ ARC Method 8 with 1-byte header (0Ch) --> nCompress 3-byte header 1Fh,9Dh,8Ch
+ ARC Method 9 without header --> nCompress 3-byte header 1Fh,9Dh,8Dh
+Method 8 does have 0Ch as first byte (indicating max 12bit codesize, this must
+be always 0Ch, the ARC decoder supports only that value). Method 9 uses max
+13bit codesize (but doesn't have any leading codesize byte).
+
+LZHUF
+This is based on LHArc lh1. Like lh1, it does have 13Ah data/len codes, and
+1000h distance codes. There are two differences:
+ Differences LHArc method lh1 ARC method 0Ah
+ Data/len codes: 100h..139h=Len(3..3Ch) 100h=End, 101h..139h=Len(3..3Bh)
+ Initial dictionary: 20h-filled Uninitialized
+
+Notes
+ARC file/directory names are alphabetically sorted, that does apply even when
+adding files to an existing archive (they are inserted at alphabetically sorted
+locations rather than being appended at end of archive).
+ARC files can be encrypted/garbled with password (via "g" option), the chunk
+header doesn't contain any flags for indicating encrypted files (except, the
+CRC16 will be wrong when not supplying the correct password).
+ARC end-marker (1Ah,00h) may be followed by additional padding bytes, or by
+additional information from third-party tools:
+ PKARC/PKPAK adds comments (starting with "PK",AAh,55h)
+ PAK adds extended records (described in PAK.DOC file in the v2.51)
+
+See also
+http://fileformats.archiveteam.org/wiki/ARC_(compression_format)
+https://www.fileformat.info/format/arc/corion.htm
+http://cd.textfiles.com/pcmedic/utils/compress/arc520s.zip - source code
+https://github.com/ani6al/arc - source code, upgraded with method 9 and 4
+https://entropymine.wordpress.com/2021/05/11/arcs-trimmed-compression-scheme/
+http://www.textfiles.com/programming/FORMATS/arc-lbr.pro - benchmarks
+
+CDROM File Compression RAR
+--------------------------
+
+RAR is a compression format for enthusiastic users (who love to download the
+latest RAR version before being able to decompress those RAR files).
+
+RAR v1.3 (March 1994, used only in RAR 1.402)
+This format was only used by RAR 1.402, and discontinued after three months
+when RAR 1.5 got released.
+ File Header:
+ 000h 4 ID "RE~^" (aka 52h,45h,7Eh,5Eh)
+ 004h 2 Header Size (usually 0007h, or bigger when Comment/Ext1 exist)
+ 006h 1 Archive Flags (80h or xxh)
+ ... (2) Archive Comment Size ;\Only present when ArchiveFlags.bit1=1
+ ... (..) Archive Comment Data ;/
+ ... (2) Ext1 Size ;\Only present when ArchiveFlags.bit5=1
+ ... (..) Ext1 Data ;/
+ ... .. Unknown (TECHNOTE hints sth can be here, when bigger HeaderSize?)
+ Archive Flags:
+ 0 Volume (maybe related to split-volume on several floppies?)
+ 1 Comment
+ 2 Unknown? (non-english description is in 1.402's TECHNOTE.DOC)
+ 3 Unknown? (non-english description is in 1.402's TECHNOTE.DOC)
+ 4 Unknown? (non-english description is in 1.402's TECHNOTE.DOC)
+ 5 EXT1
+ 6 Unspecified (maybe unused)
+ 7 Unspecified (maybe unused, but... it's usually 1)
+ File Data blocks:
+ 000h 4 Filesize, compressed
+ 004h 4 Filesize, uncompressed
+ 008h 2 Checksum on uncompressed? file (sum=LeftRotate16bit(sum+byte[i])
+ 00Ah 2 Header Size (usually 0015h+FilenameLength)
+ 00Ch 4 File Modification Timestamp in MSDOS format
+ 010h 1 File Attribute in MSDOS format (20h=Normal)
+ 011h 1 Flags
+ 012h 1 Version (0=0.99, 1=1.00, 2=1.30) (always 2 in public version)
+ 013h 1 Filename Length
+ 014h 1 Method (00h=m0a=Stored, 03h=m3a=Default) (1..5 = fastest..best)
+ ... (2) File Comment Length ;\Only present if FileFlags.bit3=1
+ ... (..) File Comment Data ;/
+ ... .. Filename ("PATH\FILENAME.EXT", without any end marker)
+ ... .. Unknown (TECHNOTE hints sth can be here, when bigger HeaderSize?)
+ ... .. Compressed file data
+ File Flags:
+ 0 Unknown? (non-english description is in 1.402's TECHNOTE.DOC)
+ 1 Unknown? (non-english description is in 1.402's TECHNOTE.DOC)
+ 2 Unknown? (non-english description is in 1.402's TECHNOTE.DOC)
+ 3 Comment (non-english description is in 1.402's TECHNOTE.DOC)
+ 4-7 Unspecified (maybe unused)
+
+RAR 1.5 (June 1994) and newer
+Overall Chunk Format:
+ 000h 2 Chunk Header CRC; Lower 16bit of CRC32 on [002h..HdrSize-1 or less]
+ 002h 1 Chunk Type (72h..7Ah)
+ 003h 2 Chunk Flags
+ 005h 2 Chunk Header Size
+ 007h (4) Data block size ;<-- Only present if Flags.bit15=1
+ ... .. Header values (depending on Chunk Type and Chunk Header Size)
+ ... .. Data block ;<-- Only present if Flags.bit15=1
+ Chunk Types:
+ 72h="r"=Marker block (with "r" being 3rd byte in ID "Rar!",1Ah)
+ 73h="s"=Archive header
+ 74h="t"=File header
+ 75h="u"=Old style Comment header (nested within Type 73h/74h)
+ 76h="v"=Old style Authenticity information
+ 77h="w"=Old style Subblock
+ 78h="x"=Old style Recovery record
+ 79h="y"=Old style Authenticity information
+ 7AH="z"=Subblock
+ Chunk Flags:
+ 0-13 Flags, meaning depends on Chunk Type
+ 14 If set, older RAR versions (before 1.52 or so?) will ignore the
+ block and remove it when the archive is updated. If clear, the
+ block is copied to the new archive file when the archive is
+ updated;
+ or does "older" mean older than the "archiver version"?
+ 15 Data Block present (0=No, 1=Yes, with size at [007h])
+
+Type 72h, Marker Block (MARK_HEAD)
+This 7-byte ID occurs at the begin of RAR files (or after the executable in
+case of self-extracting files).
+ 000h 7 ID ("Rar!",1Ah,07h,00h) (or "Rar!",1Ah,07h,01h for RAR 5.0)
+ The above ID can be somewhat parsed as normal chunk header, as so:
+ 000h 2 Faux CRC (6152h, no actual valid CRC)
+ 002h 1 Chunk Type (72h)
+ 003h 2 Faux Flags (1A21h, no actual meaning)
+ 005h 2 Chunk Header size (0007h)
+
+Type 73h, Archive Header (MAIN_HEAD)
+ 000h 2 CRC32 AND FFFFh of fields HEAD_TYPE to RESERVED2
+ 002h 1 Chunk Type: 73h
+ 003h 2 Archive HeaderFlags
+ 005h 2 Header size (usually 000Dh) (plus Comment Block, if any)
+ 007h 2 RESERVED1 (0000h)
+ 009h 4 RESERVED2 (0000011Dh)
+ ... (..) Comment block ;<-- only present if Flags.bit1=1
+ ... (..) Reserved for additional blocks
+ Archive Header Chunk Flags:
+ 0 Volume attribute (archive volume) (split-volume? volume-label? what?)
+ 1 Archive comment present ;<-- used only before RAR 3.x
+ RAR 3.x uses "the separate comment block" and does not set this flag.
+ 2 Archive lock attribute
+ 3 Solid attribute (solid archive)
+ 4 New volume naming scheme (0=Old="name.???", 1=New="name.partN.rar")
+ 5 Authenticity information present ;<-- used only before RAR 3.x
+ 6 Recovery record present
+ 7 Chunk headers are encrypted
+ 8 First volume ;<-- set only by RAR 3.0 and later
+ 9-13 Reserved for internal use
+ 14-15 See overall Chunk Format
+
+Type 74h, File Header (File in Archive)
+ 000h 2 CRC32 AND FFFFh on HEAD_TYPE to FILEATTR and file name
+ 002h 1 Header Type: 74h
+ 003h 2 Bit Flags
+ 005h 2 File header full size including file name and comments
+ 007h 4 Compressed file size (can be bigger than uncompressed)
+ 00Bh 4 Uncompressed file size
+ 00Fh 1 Operating system used for archiving
+ 010h 4 CRC32 on uncompressed file
+ 014h 4 File Modification Timestamp in MSDOS format
+ 018h 1 RAR version needed to extract file (Major*10+Minor) (min=0Fh=1.5)
+ 019h 1 Compression Method (usually 35h in RAR 1.52)
+ 01Ah 2 Filename size
+ 01Ch 4 File Attribute in MSDOS format (20h=Normal, Upper24bit=whatever=0)
+ ... (..) Comment block ;-Only present if Flags.bit3=1
+ ... (4) MSBs of compressed file size ;\Only present if Flags.Bit8=1
+ ... (4) MSBs of uncompressed file size ;/
+ ... .. Filename ("PATH\FILENAME.EXT")
+ ... (..) Filename extra fields (see Flags.bit9+bit11)
+ ... (8) Encryption SALT ;-Only present if Flags.Bit10=1
+ ... (..) Extended Time, variable size ;-Only present if Flags.Bit12=1
+ ... (..) * other new fields may appear here.
+ ... .. Compressed file data
+ File Chunk Flags:
+ 0 File continued from previous volume
+ 1 File continued in next volume
+ 2 File encrypted with password
+ 3 File comment present ;<-- used only before RAR 3.x
+ RAR 3.x uses the separate comment block and does not set this flag.
+ 4 Information from previous files is used (solid flag) ;RAR 2.0 and later
+ 5-7 Dictionary bits (for RAR 2.0 and later)
+ 8 64bit Filesizes (for files "larger than 2Gb")
+ 9 Unicode Filename, this can be in Dual or Single name form:
+ Dual name: "NormalName",00h,"UnicodeName" ;<-- in UTF-8 or what?
+ Single name: "UnicodeName" ;<-- in UTF-8
+ 10 Header contains 8-byte Encryption SALT entry
+ 11 Backup File (with version number ";n" appended to filename)
+ 12 Extended Time field present
+ 13-14 -
+ 15 Data Block present (always 1=With 32bit size at [007h], or 64bit size)
+ Dictionary Bits (bit5-7)
+ 00h=Dictionary Size 64 Kbyte
+ 01h=Dictionary Size 128 Kbyte ;\
+ 02h=Dictionary Size 256 Kbyte ; RAR 2.0 and up
+ 03h=Dictionary Size 512 Kbyte ;
+ 04h=Dictionary Size 1024 Kbyte ;/
+ 05h=Dictionary Size 2048 Kbyte ;\RAR ?? and up
+ 06h=Dictionary Size 4096 Kbyte ;/
+ 07h=File is a directory ;-RAR 2.0 and up
+ Operating System Indicators:
+ 00h=MS DOS
+ 01h=OS/2
+ 02h=Windows
+ 03h=Unix
+ 04h=Mac OS
+ 05h=BeOS
+ ??h=Android?
+ Compression Method:
+ 35h=Default in RAR 1.52 (used even when file is too small to be compressed)
+ xxh=Other methods (unknown values)
+ 30h=Stored (RAR 2.00 supports uncompressed small files and -m0 switch)
+ N/A=Stored (RAR 1.52 simply ignores "-m0" switch, and enforces "-m1" or so)
+
+Type 75h, Comment block:
+ 000h 2 Header CRC of fields from HEAD_TYPE to COMM_CRC
+ 002h 1 Chunk Type: 75h
+ 003h 2 Chunk Flags (unknown if/which flags are used)
+ 005h 2 Chunk Header size (0Eh+Compressed comment size)
+ 007h 2 Uncompressed comment size
+ 009h 1 RAR version needed to extract comment
+ 00Ah 1 Packing Method
+ 00Ch 2 Comment CRC
+ 00Eh .. Compressed comment data
+
+Sub-formats
+The RAR format is comprised of many sub-formats that have changed over the
+years. The different formats and their descriptions are as follows:
+ * 1.3 (Does not have the RAR! signature)
+ o There is difficulty finding information regarding this sub-format.
+ * 1.5
+ o Utilizes a proprietary compression method that is not public.
+ o Considered the root model of subsequent formats.
+ o A detailed list of information can be found here.
+ * 2.0
+ o Utilizes a proprietary compression method that is not public.
+ o Based off of version 1.5 of the RAR file format.
+ * 3.0
+ o Utilizes the PPMII and Lempel-Ziv (LZSS)] algorithms.
+ o Encryption now uses cipher block chaining (AES?-CBC) instead of AES
+ o Based off of version 1.5 of the RAR file format.
+
+See also
+Older RAR versions did include a TECHNOTE file describing the file format of
+those versions (TECHNOTE for 1.402 exist in unknown-language only, perhaps
+russian, and TECHNOTE was discontinued somewhere between 2.5 and 2.9).
+There is official decompression source code for newer RAR versions.
+
+CDROM File Compression ZOO
+--------------------------
+
+ZOO Archives
+ File Header:
+ 000h 20 Text Message (usually "ZOO #.## Archive.",1Ah,00h,00h)
+ 014h 4 ID (FDC4A7DCh) (use this ID for detection, and ignore above text)
+ 018h 4 Offset to first Chunk (22h or 2Ah+commentsize?)
+ 01Ch 4 Offset to first Chunk, negated (-22h or -2Ah-commentsize?)
+ 020h 1+1 Version needed to extract (Major,Minor) (usually 1,01 or 2,00)
+ 022h (1) Archive Header Type (01h) ;\
+ 023h (4) Offset to Archive Comment (0=None) ; v2.00 and
+ 027h (2) Length of Archive Comment (0=None) ; up only
+ 029h (1) Version Data (01h or 03h) "HVDATA" ;/
+ File Chunks:
+ 000h 4 ID (FDC4A7DCh)
+ 004h 1 Type of directory entry (1=Old, 2=New, with extra entries)
+ 005h 1 Compression method (0=Stored, 1=LZW/default, 2=LZH)
+ 006h 4 Offset to next Chunk
+ 00Ah 4 Offset to File Data
+ 00Eh 4 File Modification Date/time in MSDOS format
+ 012h 2 CRC16 on uncompressed file (with initial value 0000h)
+ 014h 4 Filesize, uncompressed
+ 018h 4 Filesize, compressed
+ 01Ch 1+1 Version needed to extract (Major,Minor) (usually 1,00 or 2,01)
+ 01Eh 1 Deleted flag (0=Normal, 1=Deleted)
+ 01Fh 1 File structure (unknown purpose)
+ 020h 4 Offset of comment field (0=None)
+ 024h 2 Length of comment field (0=None)
+ 026h 13 Short Filename ("FILENAME.EXT",00h, garbage padded if shorter)
+ 033h (1) Unknown (4Fh) (or 00h when with comment?) ;-Type=1
+ 033h (2) Length of 038h and up (0Ah+longname+dirname) ;\
+ 035h (1) Timezone (signed) (7Fh=Unknown) ;
+ 036h (2) CRC16 on Header (000h..037h+[033h], with [036h]=0000h) ;
+ 038h (1) Length of Long Filename (0=None, use Short Filename) ;
+ 039h (1) Length of Directory name (0=None) ; Type=2
+ 03Ah (..) Long Filename ("longfilename.ext",00h) (if any) ;
+ ... (..) Directory name ("/path",00h) (if any) ;
+ ... (2) System ID (0=Unix, 1=DOS, 2=Portable) (but for DOS=0) ;
+ ... (3) File Attributes (24bit) (but for DOS=0) ;
+ ... (1) Backup Flags (bit7=On, bit6=Last, bit0-3=Generation) ;
+ ... (2) Backup File Version Number (for backup copies) ;/
+ ... 5 File Leader aka Fudge Factor ("@)#(",00h) ;\
+ ... .. File Data ; All types
+ ... .. File Comment (if any) (ASCII, "Text string",0Ah) ;/
+ Last Chunk:
+ 000h 4 ID (FDC4A7DCh)
+ 004h (30h) Zerofilled ;-Type 1
+ 004h (1) Fixed (02h) ;\
+ 005h (31h) Zerofilled ; Tyoe 2
+ 036h (2) CRC16 on Header (with [036h]=0000h) (always 83FCh) ;/
+ ... (..) Comments may be stored here (if added after archive creation)
+ ... (..) Padding, if any (1Ah-filled in some files)
+
+Notes:
+Method LZW is quite straight, the bitstream is fetched LSB first, codesize is
+initially 9bit, max 13bit, with two special codes (100h=Clear, 101h=Stop),
+there aren't any gaps after clear codes, the unusual part is that the bitstream
+does start with a clear code.
+Method LZH is slower, requires Zoo 2.10, and is used only when specifiying "h"
+option in commandline. LZH has 8Kbyte window, same as LHA's "lh5", with an
+extra end marker (blocksize=0000h=end).
+Comments may be stored anywhere in the middle or at the end of the archive
+(even after the zerofilled last chunk) (depending on whether the comment or
+further files where last added to the archive).
+Zoo is from 1986-1991, long filenames were supported only for OSes that did
+support them at that time (ie. not for DOS/Windows).
+When adding new files, Zoo defaults to maintain backups of old files in the
+archive (older files are marked as "deleted" via [01Eh]=1, but are kept in the
+archive; until the user issues command "P" for repacking/removing deleted
+files) (Zoo 2.xx can additionally use a "generation" limit of 0..15, which
+means to keep 0..15 older copies).
+All offsets are originated from begin of archive.
+
+Zoo Tiny format (single-file) (commandline "z" option)
+This format is called Tiny in Zoo source code, but isn't documented in the Zoo
+manual or Zoo help screen. Tiny can contain only a single file (alike gzip).
+The purpose appears to be using Tiny as temporary files when moving files from
+one archive to another (without needing to decompress & recompress the file),
+for example:
+ zoo xz source.too testfile.txt ;extract to tiny/temp file testfile.tzt
+ zoo az dest.zoo testfile.txt ;import from tiny/temp file testfile.tzt
+The tiny/temp file extensions have the middle character changed to "z" (eg.
+"tzt" instead of "txt").
+Going by zoo source code, the format should look as so:
+ 000h 2 Zoo Tiny ID (07FEh)
+ 002h 1 Type (01h)
+ 003h 1 Compression Method
+ 004h 4 Date/time in MSDOS format
+ 008h 2 CRC16 on uncompressed file, or what (?)
+ 00Ah 4 Filesize, uncompressed
+ 00Eh 4 Filesize, compressed
+ 012h 1 Major_ver
+ 013h 1 Minor_ver
+ 014h 2 Comment size (0=None)
+ 016h 13 Short Filename
+ 023h .. File data ... plus comment, if any?
+But, files from Zoo DOS version are reportedly starting with 07h,01h (instead
+FEh,07h,01h).
+And, using Zoo DOS version with "z" option in Win98 does merely display "Zoo:
+FATAL: I/O error or disk full."
+
+Zoo Filter format (for modem streaming) (commandline "f" command)
+This command is documented in the Zoo manual, although it isn't actually
+supported in Zoo DOS version. The intended purpose is to use Zoo as a filter to
+speedup modem transfers.
+Going by some information snippets, the transfer format appears to be somewhat
+as so:
+ 000h 2 Zoo Filter ID (32h,5Ah)
+ ... .. Compressed data
+ ... 2 CRC16 on uncompressed file, or what (?)
+The transfer uses stdin/stdout instead of source/dest filenames (although, the
+OS commandline interface may allow to assign filenames via ">" and "<").
+There is no compression method entry (so both sides must know whether they
+shall use LZW or LZH).
+Unknown if there are any transfer size entries, or LZW/LZH end codes, or maybe
+the streaming is infinite (with CRCs inserted here ot there)?
+
+CDROM File Compression nCompress.Z
+----------------------------------
+
+nCompress is some kind of a Gzip predecessor. The program was originally called
+"compress" and later renamed to "ncompress" (and sometimes called
+"(n)compress"). Compressed files have uppercase ".Z" attached to their original
+name.
+
+nCompress.Z
+The header is rather small and lacks info on decompressed size (ie. the one
+must process the whole bitstream to determine the size, and accordingly, the
+fileformat doesn't allow padding to be appended at end of file). To detect .Z
+files, examine the first three bytes, and best also check that the leading 9bit
+codes don't exceed num_codes (with num_codes increasing from 101h and up for
+each new code).
+ 000h 2 ID (1Fh,9Dh)
+ 002h 1 Mode (MaxBits(9..16) + bit7=WithClearCode) (usually 90h)
+ 003h .. ClearGap LZW compressed data (or raw LZW when mode.bit7=0)
+Compression is relative straight LZW, resembling 8bit GIFs, with 9bit initial
+codesize, with preset codes 000h..0FFh=Data and (optional) 100h=Clear code
+(there is no End code). Codes are allocated from 101h and up (100h and up if
+without Clear code).
+The bitstream is fetched LSB first (starting in bit0 of first byte). The
+decoder is prefetching groups of eight codes (N-bytes with eight N-bit codes),
+the odd part is that Clear codes are discarding those prefetched bytes (so
+Clear codes will be followed by Gaps with unused bytes).
+ClearGap LZW is also used by ARC Method 8 and 9.
+
+CDROM File Compression Octal Oddities (TAR, CPIO, RPM)
+------------------------------------------------------
+
+Below are file formats with unix/linux-style octal numbers (unknown if they are
+serious about using that formats, or if they do consider them as decently
+amusing, or whatever).
+
+Compression
+TAR and CPIO are uncompressed archives, however, they are usually enclosed in a
+compressed Gzip file (or some other compression format like nCompress, Bzip2).
+
+TAR format (1979)
+ 0000h .. TAR Chunk(s)
+ ... 400h TAR End Marker (400h bytes zerofilled)
+ ... .. Zerofilled (whatever further padding)
+TAR Chunk format:
+ 000h 100 text Filename ("path/filename.ext",00h)
+ 064h 8 octal Mode Flags
+ 06Ch 8 octal User ID
+ 074h 8 octal Group ID
+ 07Ch 12 octal Filesize
+ 088h 12 octal File modification time (seconds since 01 Jan 1970)
+ 094h 8 octal Header Checksum (sum of byte[0..1F3h], with [94h..9Bh]=20h)
+ 09Ch 1 text Type (00h or "0" for normal files)
+ 09Dh 100 text Whatever link name
+ 101h 8 text Tar ID (6x00h or "ustar",00h,"00" or "ustar ",00h)
+ 109h 32 text User Name (owner)
+ 129h 32 text Group Name
+ 149h 8 octal Device major ;\device number (when Type="4")
+ 151h 8 octal Device minor ;/
+ 159h 155 ? Whatever prefix ;-when ID="ustar",00h,"00" or 6x00h
+ 159h 131 ? Whatever prefix ;\
+ 1DCh 12 octal File access time ; when ID="ustar ",00h
+ 1E8h 12 octal File status-change time ;/
+ 1F4h 12 - Zeropadding to 200h-byte boundary
+ 200h .. - File data (Filesize bytes)
+ ... .. - Zeropadding to 200h-byte boundary
+TAR numeric values are weirdly stored as octal ASCII strings, often decorated
+with leading or trailing spaces. For example, 8-byte octal value 123o (53h) can
+look as so (with "." meaning 00h end-byte):
+ "0000123." <-- normal weirdness, with leading zeroes and end-byte ("."=00h)
+ " 123 . " <-- extra weird, leading/trailing spaces, mis-placed end-byte
+ " 123 " <-- extra weird, leading/trailing spaces, without end-byte
+See also: https://www.gnu.org/software/tar/manual/html_node/Standard.html
+
+CPIO Format (1977) (and MAC .PAX files)
+ 0000h .. CPIO Chunk(s) (with actual files)
+ ... 57h CPIO Chunk (with filename "TRAILER!!!",00h)
+ ... .. Zeropadding to 200h-byte boundary (not always present)
+The chunks are simple, but they do exist in five weirdly different variants:
+ Align 2, Binary, little-endian (but partial "big-endian" for 2x16bit pairs)
+ Align 2, Binary, big-endian
+ Align 1, Ascii, octal strings
+ Align 4, Ascii, hexadecimal lowercase strings, checksum=0)
+ Align 4, Ascii, hexadecimal lowercase strings, checksum=sum of bytes in file)
+Binary, little-or-big-endian:
+ 000h 2 binary 16bit ID (71C7h) ;-little-or big endian
+ 002h 2 binary 16bit dev ;\
+ 004h 2 binary 16bit ino ; same
+ 006h 2 binary 16bit mode ; endianness
+ 008h 2 binary 16bit uid ; as in ID
+ 00Ah 2 binary 16bit gid ;
+ 00Ch 2 binary 16bit nlink ; (but be aware
+ 00Eh 2 binary 16bit rdev ; of the fixed
+ 010h 2 binary 16bit File modification time, upper 16bit ;\ ; upper/lower
+ 012h 2 binary 16bit File modification time, lower 16bit ;/ ; 16bit order
+ 014h 2 binary 16bit Filename size (including ending 00h) ; for time and
+ 016h 2 binary 16bit Filesize, upper 16bit ;\ ; filesize)
+ 018h 2 binary 16bit Filesize, lower 16bit ;/ ;/
+ 01Ah .. text Filename, terminated by 00h ("path/filename",00h)
+ ... .. binary Zeropadding to 2-byte boundary
+ ... .. binary File data (Filesize bytes)
+ ... .. binary Zeropadding to 2-byte boundary
+Ascii/octal CPIO Chunk format:
+ 000h 6 octal 18bit ID "070707" (=71C7h)
+ 006h 6 octal 18bit dev ;\unique file id
+ 00Ch 6 octal 18bit ino ;/within archive
+ 012h 6 octal 18bit Mode (file attributes)
+ 018h 6 octal 18bit User ID of owner
+ 01Eh 6 octal 18bit Group ID
+ 024h 6 octal 18bit nlink (related to duplicated dev/ino?)
+ 02Ah 6 octal 18bit rdev (system-defined info on char/blk devices)
+ 030h 11 octal 33bit File modification time
+ 03Bh 6 octal 18bit Filename size (including ending 00h)
+ 041h 11 octal 33bit Filesize
+ 04Ch .. text Filename, terminated by 00h ("path/filename",00h)
+ ... .. binary File data (Filesize bytes)
+Ascii/hex CPIO Chunk format:
+ 000h 6 hex 24bit ID "070701"=Without Checksum, or "070702"=With Checksum
+ 006h 8 hex 32bit ino (does that 32bit value include 16bit "dev"?)
+ 00Eh 8 hex 32bit mode
+ 016h 8 hex 32bit uid
+ 01Eh 8 hex 32bit gid
+ 026h 8 hex 32bit nlink
+ 02Eh 8 hex 32bit mtime
+ 036h 8 hex 32bit Filesize
+ 03Eh 8 hex 32bit devmajor
+ 046h 8 hex 32bit devminor
+ 04Eh 8 hex 32bit rdevmajor
+ 056h 8 hex 32bit rdevminor
+ 05Eh 8 hex 32bit Filename size (including ending 00h)
+ 066h 8 hex 32bit Checksum, sum of all bytes in file, zero when ID=070701
+ 06Eh .. text Filename, terminated by 00h ("path/filename",00h)
+ ... .. binary Zeropadding to 4-byte boundary
+ ... .. binary File data (Filesize bytes)
+ ... .. binary Zeropadding to 4-byte boundary
+CPIO numeric values are weird octal ASCII strings (eg. 6-byte "000123"), but,
+unlike TAR, without extra oddities like spaces or end-bytes.
+https://www.systutorials.com/docs/linux/man/5-cpio/
+
+RPM Format (1997) (BIG-ENDIAN)
+RPM files contain Linux installation packages. The RPM does basically contain a
+CPIO archive bundled with additional header/records with installation
+information.
+ 000h 60h File Header (officially called "Lead" instead of "Header")
+ 060h .. Signature Record (contains "Header Record" in "Signature format")
+ ... .. Padding (to 8-byte boundary)
+ ... .. Info Record (called "Header" and also uses "Signature format")
+ ... .. Archive file (usually a GZIP compressed CPIO) (called "Payload")
+File Header (aka Lead) (60h bytes):
+ 000h 4 File ID (EDh,ABh,EEh,DBh) (aka octal string "\355\253\356\333")
+ 004h 1 Major version (3)
+ 005h 1 Minor version (0)
+ 006h 2 Type (0=Binary Package, 1=Source Package)
+ 008h 2 Architecture ID (defined in ISO/IEC 23360)
+ 00Ah 66 Package name, terminated by 00h
+ 04Ch 2 Operating System ID (1)
+ 04Eh 2 Signature Type (5)
+ 050h 16 Reserved space (officially undefined, usually zerofilled)
+Signature/Info Records (10h+N*10h+SIZ bytes):
+ 000h 4 Record ID (8Eh,ADh,E8h,01h) (aka octal string "\216\255\350\001")
+ 004h 4 Reserved (zerofilled) (aka octal string "\000\000\000\000")
+ 008h 4 Number of Item List entries (N)
+ 00Ch 4 Size of Item Data (SIZ)
+ 010h N*10h Item List (4x32bit each: Tag, Type, Offset, Size)
+ ... SIZ Item Data (referenced via Offset/Size entries in above list)
+Item Type values:
+ 00h=NULL Not Implemented
+ 01h=CHAR Unknown, maybe unsigned 8bit (unaligned)
+ 02h=INT8 Unknown, maybe signed 8bit (unaligned)
+ 03h=INT16 Unknown, maybe signed 16bit (align2)
+ 04h=INT32 Unknown, maybe signed 323bit (align4)
+ 05h=INT64 Reserved, maybe signed 643bit (maybe align8)
+ 06h=STRING Variable, NUL terminated string (unaligned)
+ 07h=BIN Unknown, reportedly 1-byte size??? (unaligned)
+ 08h=STRING_ARRAY Variable, Sequence of NUL terminated strings (unaligned)
+ 09h=I18NSTRING Variable, Sequence of NUL terminated strings (unaligned)
+Item Tag values:
+ There are dozens of required & optional tag values defined.
+RPM source code packages are often bundled with a .spec file (inside of the
+CPIO archive), that .spec file contains source code in text format for creating
+the RPM header/records.
+
+File Extensions
+ Basic extensions:
+ .cpio (CPIO)
+ .pax (CPIO for MAC)
+ .rpm (RPM installation package for RPM package manager)
+ .spec (RPM source file for creating RPM header/records)
+ .tar (TAR, tape archive)
+ Double extensions (and short forms like tgz):
+ .tgz short for .tar.gz (gzip)
+ .tbz short for .tar.bz2 (bzip2)
+ .txz short for .tar.xz (XZ)
+ .tlz short for .tar.lz (Lzip) or .tar.lzma (LZMA_Alone)
+ .tsz short for .tar.sz (Sunzip)
+ .taz short for .tar.Z (nCompress or possibly some other compressed format)
+ .tz short for .tar.Z (nCompress or possibly some other compressed format)
+ .spm short for .src.rpm (RPM source code package)
+
+CDROM File Compression MacBinary, BinHex, PackIt, StuffIt, Compact Pro
+----------------------------------------------------------------------
+
+Below are related to MAC filesystems (where the file body consists of separate
+Data and Resource forks), and file type/creator values (resembling filename
+extensions).
+
+MacBinary I,II,III format (v1,v2,v3)
+MacBinary contains a single uncompressed file, used for transferring MAC files
+via network, or storing MAC files on non-MAC filesystems.
+PackIt/StuffIt archives do often have leading MacBinary headers. MacBinary
+doesn't have any unique filename extension (.bin may be used, more often it's
+using the same extension as the enclosed file, eg. .sit if it contains a
+StuffIt archive).
+Also, archives without explicit MAC support may use MacBinary format within
+compressed files (eg. LZH archives created with LHA MAC version).
+ 000h 1 Old version number, must be kept at zero for compatibility
+ 001h 1 Length of filename (1..63) (though v3 says 1..31)
+ 002h 63 Filename (only "length" bytes are significant)
+ 041h 4 File type (normally expressed as four characters)
+ 045h 4 File creator (normally expressed as four characters)
+ 049h 1 Finder flags, bit8-15 (see [065h] for bit0-7)
+ 04Ah 1 Zero (must be 00h for compatibility)
+ 04Bh 2 File Vertical position within its window
+ 04Dh 2 File Horizontal position within its window
+ 04Fh 2 File Window or folder ID
+ 051h 1 Protected flag (bit0=Protected, whatever that is)
+ 052h 1 Zero (must be 00h for compatibility)
+ 053h 4 Filesize, Data Fork (0=None)
+ 057h 4 Filesize, Resource Fork (0=None)
+ 05Bh 4 File Timestamp, creation
+ 05Fh 4 File Timestamp, last modification
+ 063h 27 v1: Reserved (zerofilled)
+ 063h 2 v2/v3: Length of Get Info comment (if any, usually 0000h)
+ 065h 1 v2/v3: Finder Flags, bit0-7 (see [049h] for bit8-15)
+ 066h 6 v2: Reserved (zerofilled)
+ 066h 4 v3: ID ("mBIN"=MacBinary III)
+ 06Ah 1 v3: Script of file name (from fdScript field of an fxInfo record)
+ 06Bh 1 v3: Extended Finder flags (from fdXFlags field of fxInfo record)
+ 06Ch 8 v2/v3: Reserved (zerofilled)
+ 074h 4 v2/v3: Length of "total files" when "packed files are unpacked", uh?
+ 078h 2 v2/v3: Extended Header size (reserved for future, always 0000h)
+ 07Ah 1 v2/v3: MacBinary II uploader version (81h=v2, 82h=v3)
+ 07Bh 1 v2/v3: MacBinary II downloader minimum version (81h=v2)
+ 07Ch 2 v2/v3: CRC16-XMODEM on [000h..07Bh]
+ 07Eh 2 Reserved for computer type and OS ID (0000h)
+ ... .. Extended Header (if any, maybe stored here? when [078h]>0)
+ ... .. Padding to 80h-byte boundary
+ ... .. Data Fork (if any)
+ ... .. Padding to 80h-byte boundary
+ ... .. Resource Fork (if any)
+ ... .. Padding to 80h-byte boundary
+ ... .. Get Info comment (if any, usually none)
+CRC16-XMODEM: http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
+
+BinHex 4.0 (.hqx) (ASCII, RLE90, big-endian)
+Decoding binhex files is done via following steps (in that order):
+ 1) ASCII to BINARY conversion (similar to BASE64)
+ 2) RLE90 decompression of whole file (header+data+resource+crc's)
+ 3) Processing the header+data+resource from the decompressed binary
+ 4) For Multipart files, repeat above steps for each part
+ASCII to BINARY:
+ The file may start with some text message, comments, description. Skip any
+ such text lines until reaching a line that contains this 45-byte ID string:
+ (This file must be converted with BinHex 4.0)
+ That line should be followed by following characters (each char representing
+ 6bit binary value, MSB first, first char is bit7-2 of first byte):
+ !"#$%&'()*+,- char(21h..2Dh) --> bin(00h..0Ch)
+ 0123456 char(30h..36h) --> bin(0Dh..13h)
+ 89 char(38h..39h) --> bin(14h..15h)
+ @ABCDEFGHIJKLMN char(40h..4Eh) --> bin(16h..24h)
+ PQRSTUV char(50h..56h) --> bin(25h..2Bh)
+ XYZ[ char(58h..5Bh) --> bin(2Ch..2Fh)
+ `abcdef char(60h..66h) --> bin(30h..36h)
+ hijklm char(68h..6Dh) --> bin(37h..3Ch)
+ pqr char(70h..72h) --> bin(3Dh..3Fh)
+ : char(3Ah) --> start/end marker
+ CR/LF char(0Dh/0Ah) --> linebreaks per 64 chars (CR and/or LF)
+ SPC/TAB char(09h/20h) --> blanks (reportedly in some files)
+RLE90 Decompression:
+ RLE90 decompression is same as in ARC files, except, code 90h,00h is handled
+ differently: ARC keeps prevbyte=unchanged, BinHex sets prevbyte=90h.
+ RLE90 compression is somewhat optional: 90h must be encoded as 90h,00h,
+ but many encoders don't bother to compress repeating bytes (eg. many files
+ contain "!!!!!!!!" chars aka uncompressed 00h-filled bytes).
+ There is no way to know the decompressed size before decompression (either
+ decompress the whole file and allocate more memory as needed, or decompress
+ only the header (filename+16h bytes) and then compute decompressed size as
+ filename+16h+data+2+resource+2 bytes).
+Decompressed Binary (big-endian):
+ The decompressed binary contains following data (similar as MacBinary):
+ 00h 1 Length of Filename (1..63)
+ 01h .. Filename ("FILENAME.EXT")
+ 01h+N 1 Version (00h)
+ 02h+N 4 File Type
+ 06h+N 4 File Creator
+ 0Ah+N 2 Finder Flags
+ 0Ch+N 4 Filesize, uncompressed, Data Fork
+ 10h+N 4 Filesize, uncompressed, Resource Fork
+ 14h+N 2 Header CRC16-XMODEM on uncompressed 14h+N bytes
+ 16h+N .. Data Fork
+ ... 2 Data Fork CRC16-XMODEM on uncompressed Data Fork
+ ... .. Resource Fork
+ ... 2 Resource Fork CRC16-XMODEM on uncompressed Resource Fork
+ ... .. Padding (might reportedly occur in some files)
+ Caution: There is a document that does claim that the CRC field should be be
+ set to 0000h before CRC calculation, and that the CRC would be computed on
+ Size+2 bytes (up to including he CRC field), that appears to be nonsense,
+ the CRC is computed on Size+0 bytes, not Size+2.
+Multipart files:
+ Emails or other text documents may contain multiple binhex files, if so,
+ each part should be reportedly followed by a line containing:
+ --- end of part NN ---
+ Unknown if there are any .hqx files with such multipart stuff.
+ Unknown if the next part starts with "(This file must.." or just with ":".
+Note: Many files with .hqx extension are actually raw .sit or .cpt files (maybe
+because somebody had removed the binhex encoding without altering the filename
+extension).
+
+PackIt (.pit) (Macintosh) (1986) (big-endian)
+MAC File Type,Creator IDs = "PIT ","PIT " <-- normal (=uncompressed?)
+MAC File Type,Creator IDs = "PIT ","UPIT" <-- other (=compressed?)
+ Bitstream for Uncompressed File Entries:
+ 32bits Uncompressed Header[000h..003h] (Method/Crypto="PMag")
+ ..bits Uncompressed Header[004h..061h] (uncompressed size = 5Eh)
+ ..bits Uncompressed Data+Resource+CRC (uncompressed size = Data+Rsrc+2)
+ Bitstream for Compressed File Entries:
+ 32bits Uncompressed Header[000h..003h] (Method/Crypto="PMa4")
+ ..bits Compressed Huffman Tree (for decoding following bits)
+ ..bits Compressed Header[004h..061h] (uncompressed size = 5Eh)
+ ..bits Compressed Data+Resource+CRC (uncompressed size = Data+Rsrc+2)
+ ..bits Padding to 8bit-boundary (byte align next File Entry)
+ Bitstream for Archive End Marker (after last file):
+ 32bits Uncompressed Header[000h..003h] (Method/Crypto="PEnd")
+ File Entry Format:
+ 000h 4 Method/Crypto (usually "PMag"=Uncompressed, "PMa4"=Huffman)
+ 004h 1 Filename length
+ 005h 63 Filename ("FILENAME", garbage padded)
+ 044h 4 File Type
+ 048h 4 File Creator
+ 04Ch 2 Finder flags
+ 04Eh 2 Locked?
+ 050h 4 Filesize, uncompressed, Data fork
+ 054h 4 Filesize, uncompressed, Resource fork
+ 058h 4 Timestamp, creation
+ 05Ch 4 Timestamp, modification
+ 060h 2 CRC16-XMODEM on [004h..05Fh]
+ ... .. Data Fork
+ ... .. Resource Fork
+ ... 2 CRC16-XMODEM on uncompressed Data+Resource forks
+ Method/Crypto:
+ "PEnd" = Archive End marker (4-byte end marker, without filename etc.)
+ "PMag" = Uncompressed
+ "PMa1" = Uncompressed, Encrypted Simple
+ "PMa2" = Uncompressed, Encrypted DES
+ "PMa3" = Uncompressed, Encrypted reserved
+ "PMa4" = Huffman
+ "PMa5" = Huffman, Encrypted Simple
+ "PMa6" = Huffman, Encrypted DES
+ "PMa7" = Huffman, Encrypted reserved
+ Decompression: ;for PackIt (and also for StuffIt method 03h)
+ InitBitstreamMsbFirst(src) ;-src is after "PMa4" PackIt ID
+ tree=GetMem(200h*4) ;-alloc tree (probably less needed)
+ num_entries=0 ;\init tree
+ root=GetTreeEntry ;/
+ while dst<dst_end ;-decompress, till end...
+ index=root ;\
+ while index<FF00h ; huffman decode
+ index=[tree+index*4+GetBits(1)*2] ;/
+ [dst]=index AND FFh, dst=dst+1 ;-store data
+ return
+ ;---
+ GetTreeEntry:
+ if GetBits(1)=1 then
+ return GetBits(8)+FF00h ;-final data entry
+ else
+ index=num_entries ;-current index
+ num_entries=num_entries+1 ;-alloc next index
+ [tree+index*4+0*2] = GetTreeEntry ;-recursive call for node0
+ [tree+index*4+1*2] = GetTreeEntry ;-recursive call for node1
+ return index
+http://www.network172.com/early-mac-software/packit-source-code/ - official
+
+StuffIt (.sit) (Macintosh) (old format) (1987) (big-endian)
+MAC File Type,Creator IDs = "SIT!","SIT!" (version=01h).
+MAC File Type,Creator IDs = "SITD","SIT!" (version=02h).
+MAC File Type,Creator IDs = "APPL","STi0" (whatever, with ID="ST65")
+ StuffIt Archive Header:
+ 000h 4 ID ("SIT!", short for StuffIt)
+ Reportedly, there are several alternate IDs:
+ "SIT!","ST46","ST50","ST60","ST65","STin","STi2","STi3","STi4"
+ Unknown why, and if some do differ somehow (ST65 appears to be
+ same as SIT!) (for STi, the "i" might be short for it? installer?)
+ 004h 2 Number of entries in root directory
+ 006h 4 Total size of archive
+ 00Ah 4 ID ("rLau", short for Raymond Lau)
+ 00Eh 1 Version number (01h=v1.x-v1.5.x, 02h=v1.6-v4.5)
+ 00Fh 7 Reserved (zerofilled) ;-when version=01h
+ 00Fh 1 Unknown (C6h or FFh) ;\
+ 010h 4 Offset to first root entry (16h or elsewhere!) ; when version=02h
+ 014h 2 Unknown (0001h or FFFFh) ;/
+ File Entries:
+ 000h 1 Compression method, Resource fork
+ 001h 1 Compression method, Data fork
+ 002h 1 Filename length (1..63 for version=01h, 1..31 for version=02h)
+ 003h 1Fh Filename ("FILENAME.EXT", garbage padding)
+ 022h 20h Filename further chars ;-when version=01h
+ 022h 2 Filename+size CRC ;\
+ 024h 2 Unknown (always 0000h or 0986h?) ; when version=02h
+ 026h 4 Unknown Resource fork related ;maybe window ;
+ 02Ah 4 Unknown Data fork related ;coords ? ;
+ 02Eh 1 Unknown Data fork related ;
+ 02Fh 1 Unknown Resource fork related ;
+ 030h 2 Number of child entries (excluding End marker) ;
+ 032h 4 Offset to previous entry ;
+ 036h 4 Offset to next entry ;
+ 03Ah 4 Offset to parent entry ;
+ 03Eh 4 Offset to first child (or -1 for file entries) ;/
+ 042h 4 File type (eg. "APPL")
+ 046h 4 File creator (eg. "ACTA")
+ 04Ah 2 Finder flags (2100h)
+ 04Ch 4 Creation date
+ 050h 4 Modification date
+ 054h 4 Filesize, uncompressed, Resource fork (0=None)
+ 058h 4 Filesize, uncompressed, Data fork (0=None)
+ 05Ch 4 Filesize, compressed, Resource fork (0=None)
+ 060h 4 Filesize, compressed, Data fork (0=None)
+ 064h 2 CRC16 on uncompressed(?) Resource fork (0=None)
+ 066h 2 CRC16 on uncompressed(?) Data fork (0=None)
+ 068h 1 Pad bytes for encrypted Resource? (00h)
+ 069h 1 Pad bytes for encrypted Data? (00h)
+ 06Ah 2 Unknown Data fork related (0000h, or 0004h=Encrypted?)
+ 06Ch 2 Unknown Resource fork related (0000h, or 0004h=Encrypted?)
+ 06Eh 2 CRC16 on Header [000h..06Dh] with initial=0000h
+ 070h .. Compressed Data, Resource fork (if any) (size=[05Ch])
+ ... .. Compressed Data, Data fork (if any) (size=[060h])
+ StuffIt Methods:
+ 00h Uncompressed
+ 01h RLE90 (same as... unknown if this is like BinHex, or like ARC)
+ 02h ClearGap LZW (same as nCompress, 14bit, with Clear(+gap), no Stop code)
+ 03h Huffman (same as PackIt "PMa4" method)
+ 05h LZHUF (same as LHA "lh1" method)
+ 06h Fixed Huffman Segmented. PackBits, then optional Huffman coding.
+ The set of Huffman codes is predefined, but the meaning
+ of a code can be different in each segment
+ 08h MW (Miller-Wegman, presumably LZMW)
+ 0Dh LZ+Huffman (?) ;-StuffIt and StuffIt5
+ 0Eh Installer (uh?)
+ 0Fh Arsenic (BWT and arithmetic coding) ;-StuffIt5 only?
+ 1xh Encrypted methods (same as above, plus encryption)
+ 20h Folder start ;\StuffIt (not StuffIt5)
+ 21h Folder end ;/
+Common methods are 02h,03h,0Dh (rarely also 00h,01h,05h) (and 0Fh for
+StuffIt5).
+Folders have BOTH methods set to 20h. Uncompressed Data size is WHAT? (maybe
+sum of all decompressed files in that folder?) Compressed Data size is size in
+SIT file including 70h-byte folder end-marker. The Folder END marker has both
+methods set to 21h. The Folder END marker has NONSENSE data size entries?
+When version=01h (eg. blackfor.sit), folder/file entries start at offset 16h,
+and are ordered as so:
+ Folder start
+ Child entries
+ Folder end
+ Folder start
+ Child entries
+ Folder end
+When version=02h (eg. cabletron.sit), folder/file entries start at offset from
+archive header [010h] (which can be anywhere at offset 16h, or near end of
+archive), and are ordered as specified in file header entries [022h..041h].
+
+StuffIt 5 (.sit) (Macintosh, Windows) (1997) (big-endian)
+ StuffIt Archive Header:
+ 000h 82 ID "StuffIt (c)1997",...,"/StuffIt/",0Dh,0Ah,1Ah,00h)
+ 052h 1 Version (always 05h)
+ 053h 1 Flags (can be 00h, 10h, 80h) (bit4=what?, bit7=Encrypted)
+ 054h 4 Total size of archive
+ 058h 4 Offset to first entry in root directory (64h, plus Extra Data)
+ 05Ch 2 Number of entries in root directory
+ 05Eh 4 Same as [058h] (maybe one is 1st entry, and other is Header size)?
+ 062h 2 Header CRC16 on [000h..[05xh]-1] with [062h]=0000h and initial=0
+ 064h .. Extra Data (see below)
+ ... .. File/Folder entries
+ Extra data can be:
+ None (when [58h]=64h) ;with Flags=00h
+ 05h,76h,35h,B9h,87h,11h ;maybe 05h=Length? ;with Flags=80h=crypto
+ 0Dh,A5h,A5h,"Reserved",A5h,A5h,00h) ;maybe 0Dh=Length? ;with Flags=10h=what?
+ File/Folder entries:
+ 000h .. Base Header
+ ... .. OS Header (depending on OS Type in Base Header)
+ ... .. Resource fork (if any) (MAC only, not Windows)
+ ... .. Data fork (if any)
+ Base Header:
+ 000h 4 ID (A5A5A5A5h) (or B4B4B4B4h=corrupted charset conversion maybe?)
+ 004h 1 OS Type (1=Mac, 3=Windows)
+ 005h 1 Unknown (0)
+ 006h 2 Base Header size (41h) (30h+IV?+Filename+Comment)
+ 008h 1 Unknown (0) (maybe Flags MSB?)
+ 009h 1 Flags (bit3=Comment, bit6=Folder, bit5=Encrypted)
+ 00Ah 4 Timestamp, Creation (Mac OS format, seconds since 1904)
+ 00Eh 4 Timestamp, Modification (Mac OS format, seconds since 1904)
+ 012h 4 Offset of previous entry (0=None)
+ 016h 4 Offset of next entry (0=None)
+ 01Ah 4 Offset of parent folder entry (0=None)
+ 01Eh 2 Filename size (F)
+ 020h 2 Base Header CRC-16 on [000h..[006h]-1]
+ 022h (4) Offset of first child entry in folder (FFFFFFFFh=End) ;\Folder
+ 026h (4) Size of complete directory ; (if Flags
+ 02Ah (4) Unknown ; bit6=1)
+ 02Eh (2) Number of child entries (excluding folder End marker) ;/
+ 022h (4) Data fork uncompressed size ;\
+ 026h (4) Data fork compressed size ;
+ 02Ah (2) Data fork CRC-16 (0 for method 0Fh) ; File
+ 02Ch (2) Data fork Unknown (0000h) ; (if Flags
+ 02Eh (1) Data fork compression method (00h,0Dh,0Fh) ; bit6=0)
+ 02Fh (1) Data fork Encryption IV? size ;
+ ... (..) Data fork Encryption IV? data ;/
+ ... .. File/Folder name ("FILENAME.EXT")
+ ... (2) Comment size (K) ;\Comment
+ ... (2) Comment Unknown (0) ; (if Flags
+ ... (..) Comment data ;/bit3=1)
+ OS Header for Mac (OS=1):
+ 000h 2 Flags2 (bit0=HasResource, bit4=same as archive header [053h] ?)
+ 002h 2 CRC16 on OS Header (with [002h]=0000h, initial=0)
+ 004h 4 Mac OS file type ;\
+ 008h 4 Mac OS file creator ; as so for Files
+ 00Ch 2 Mac OS Finder flags ; (seems to contain
+ 00Eh 2 Mac OS Unknown ; other stfuff/junk
+ 010h 4 Mac OS Unknown ; for Folders)
+ 014h 4 Mac OS Unknown ;
+ 018h 4 Mac OS Unknown ;
+ 01Ch 4 Mac OS Unknown ;
+ 020h 4 Mac OS Unknown ;/
+ 024h (4) Resource fork uncompressed size ;\
+ 028h (4) Resource fork compressed size ; only if
+ 02Ch (2) Resource fork CRC-16 (0 for method 0Fh) ; Flags2
+ 02Eh (2) Resource fork Unknown ; bit0=1
+ 030h (1) Resource fork compression method ;
+ 031h (1) Resource fork Encryption IV? size ;
+ ... (..) Resource fork Encryption IV? data ;/
+ OS Header for Windows (OS=3):
+ 000h 2 Flags 2 (bit4=same as archive header [053h] ?)
+ 002h 2 CRC16 on OS Header (with [002h]=0000h, initial=0)
+ 004h 4 Windows File Attribute (20h=Normal, 10h=Folder)
+ 008h 08h Windows Zerofilled
+ 010h 4 Windows Timestamp last accessed?
+ 014h 4 Windows Unknown (0005xxxxh)
+ 018h 08h Windows Zerofilled
+StuffIt 5 seems to only use 00h, 0Dh and 0Fh. See "StuffItSpecs" for
+descriptions of the algorithms.
+
+StuffIt X (.sitx) (Macintosh, Windows) (20xx?)
+ StuffIt Archive Header:
+ 000h 8 ID "StuffIt!" (reportedly "StuffIt?" also exists)
+ 008h .. Unknown...
+The StuffIt X headers are somehow compressed/compacted (there are very few 00h
+bytes even when filesize entries should have zeroes in MSBs).
+https://github.com/incbee/Unarchiver/blob/master/XADMaster/XADStuffItXParser.m
+
+Compact Pro aka Compactor (.cpt) (Macintosh) (1990s) (big-endian)
+MAC File Type,Creator IDs = "PACT","CPCT".
+Compact Pro (originally called Compactor) was a MAC archiver competing with
+StuffIt. There's also a DOS tool (ExtractorPC) for extracting .cpt files on PCs
+(albeit released in .EXE.sit.hqx format, making it unlikely that PC users could
+have used it).
+ Archive header:
+ 000h 1 File ID (always 01h)
+ 001h 1 Volume number (01h for single-volume, Other=Unknown)
+ 002h 2 Random Volume ID? (...must be same in all split volume files?)
+ 004h 4 Offset to Footer (from begin of file)
+ 008h .. Compressed files (resource+data fork pairs)
+ ... .. Footer (directory information)
+ Footer format:
+ 000h 4 CRC32 XOR FFFFFFFFh on following bytes
+ 004h 2 Number of entries in root folder (including all child entries)
+ 006h 1 Comment length (usually 00h=None)
+ 007h N Comment
+ 007h+N .. File/Folder entries
+ Folder entries, with [000h].bit=1:
+ 000h 1 Foldername length (N), plus bit7=Type (1=Folder)
+ 001h N Foldername ("FOLDERNAME")
+ 001h+N 2 Number of entries in this folder (including all child entries)
+ File entries, with [000h].bit=0:
+ 000h 1 Filename length (N), plus bit7=Type (0=File)
+ 001h N Filename ("FILENAME.EXT")
+ 001h+N 1 Volume number (01h for single-volume, Other=Unknown)
+ 002h+N 4 Offset to compressed Resource (followed by compressed Data)
+ 006h+N 4 File type
+ 00Ah+N 4 File creator
+ 00Eh+N 4 Timestamp, creation (seconds since 1904)
+ 012h+N 4 Timestamp, modification (seconds since 1904)
+ 016h+N 2 Finder flags
+ 018h+N 4 CRC32 XOR FFFFFFFFh on uncompressed Resource + Data forks
+ 01Ch+N 2 Method/Flags (see below)
+ 01Eh+N 4 Filesize, uncompressed, Resource fork
+ 022h+N 4 Filesize, uncompressed, Data fork
+ 026h+N 4 Filesize, compressed, Resource fork
+ 02Ah+N 4 Filesize, compressed, Data fork
+ Method/Flags:
+ 0 Encryption (0=None, 1=Encrypted, unknown how)
+ 1 Method for Resource fork (0=RLE8182, 1=RLE8182+LZSSHUF)
+ 2 Method for Data fork (0=RLE8182, 1=RLE8182+LZSSHUF)
+ 3-15 Unknown/unused (0)
+ Note: RLE8182 and RLE8182+LZSSHUF are also used by Mac DiskDoubler.
+RLE8182 Compression:
+ This is same as RLE90, with two-byte escape code (81h,82h instead of 90h):
+ 81h,82h,00h Output 81h,82h
+ 81h,82h,01h..03h Output prevbyte 00h..02h times (this is not useful)
+ 81h,82h,04h Output prevbyte 03h times (useful if prev=81h, next=82h)
+ 81h,82h,05h..FFh Output prevbyte 04h..FEh times (this does save memory)
+ 81h,xxh Output 81h, and then process xxh
+ 81h,padding Output 81h, at end of file (with padding<>82h)
+ xxh Output xxh (unless it is 81h)
+ Note: prevbyte is the previous output byte (ie. that stored at [dst-1]).
+ If the uncompressed file ends with 81h, then the compressed file MUST contain
+ a dummy padding byte (the RLE decoder in macutils sets a prefix flag upon 81h,
+ but doesn't output it to dst until receiving the padding byte, which could be
+ 81h, or any value other than 82h).
+LZSSHUF Compression:
+ This uses LZSS-style flag bits (to distinguish between data and len/disp),
+ combined with three Huffman trees (for data, len, disp values). The sliding
+ window is 2000h bytes (8Kbytes). The format appears to be a simplified variant
+ or LHA compression (but gets complicated by inventing weird corner cases).
+DecompressLzsshuf:
+ if uncompressed_size=0 then goto @@all_done ;-empty (eg. for unused forks)
+ [dst+0000h..1FFCh]=uninitialized ;\
+ [dst+1FFDh..1FFFh]=00h,00h,00h ; prefill sliding window
+ dst+dst+2000h ;/
+ @@block_lop:
+ InitBitstreamMsbFirst(src)
+ GetLzsshufTree(data_tree,100h) ;tree for data=00h..FFh
+ GetLzsshufTree(len_tree,40h) ;tree for len=00h..3Fh (0,1 usually unused)
+ GetLzsshufTree(disp_tree,80h) ;tree for dispUpper7bit=00h..7Fh
+ block_org=src, blocksize=0 ;block origin (after above trees)
+ @@decompress_lop:
+ if src>=src_end then goto @@all_done ;<-- this may overshoot on padding bits
+ if out>=out_end then goto @@all_done ;<-- more precise; if RleOnTheFly
+ if blocksize>=1FFF0h AND type=CompactPro then goto @@block_done
+ if blocksize>=0FFF0h AND type=Disc Double then goto @@block_done
+ if GetBits(1)=1 then
+ [dst]=GetHuffCode(data_tree), dst=dst+1, blocksize=blocksize+2
+ else
+ len=GetHuffCode(len_tree)+0, blocksize=blocksize+3
+ disp=GetHuffCode(disp_tree)*40h+GetBits(6), if disp=0000h then disp=2000h
+ for i=1 to len, [dst]=[dst-disp], dst=dst+1, next i
+ if RleOnTheFly then forward above byte(s) to RLE (which advances "out" ptr)
+ goto @@decompress_lop
+ @@block_done:
+ ;the decoder does prefetch data in 16bit units, and it does always have
+ ;16..31 bits prefetched, these bits are discarded at block end...
+ src=src+2+((src-block_org) AND 1) ;discard 16..31 bits (till 16bit-boundary)
+ goto @@block_lop ;start next block, with new trees
+ @@all_done:
+ ret
+GetLzsshufTree(tree,max):
+ num=GetBits(8)*2, if num>max then goto error ;number of symbols (00h and up)
+ for i=0 to num-1, codesizes[i]=GetBits(4) ;sizes (1..15 bits, or 0=unused)
+ lzh_explode_tree(tree,codesizes,num) ;alike LHA trees
+ ret
+Minor Corner cases:
+ Disp=0 acts as Disp=2000h (don't care when using ringbuf[index AND 1FFFh])
+ Len=0..1 could be definied in the len_tree (but are usually size=0bit=unused)
+ Unknown if disp_tree & len_tree can be empty (when using data_tree only)?
+ RLE ending with 81h,padding should only output 81h (see RLE8182 description)
+Incomplete Trees
+ A few .cpt files (eg. ABC's-1.09.cpt.hqx\..\Colin's ABC's\Message.h) have
+ incomplete trees (like only one disp code, "0"=DispUpper7bit=00h, without
+ defining any further huffman codes like "1" or "1xxx").
+ This isn't much of a problem (except, one may need to remove incomplete tree
+ error checking in the "lzh_explode_tree" function).
+End of Last Block
+ End of Last Block is usually determined by forwarding the LZSSHUF output
+ directly to the RLE8182 decompressor (which does then check if uncompressed
+ size is reached) (marked "RleOnTheFly" in above sample code).
+ Alternately, one could decompress in separate steps (LZSSHUF to tempbuf, and
+ then tempbuf to RLE8182), but that requires to deal with padding bits.
+ - padding seems to be 16..31 bits (?) alike at end of blocksize
+ - padding bits are (always?) zeroes, which act as flag=0=compressed
+ - compressed data occupies at least flg(1),len(1),disp(1),displsbs(6)=9bits
+ That can lead to decoding a few extra codes (with lengths up to 3Fh each),
+ so the tempbuf must have trailing space for writing that garbage padding.
+ And, those padding bits tend to translate to disp=0000h (aka disp=2000h),
+ which can cause reads from the whole sliding window, so tempbuf requires
+ 2000h leading bytes to avoid page faults (not just the 3 initialized bytes).
+See also:
+https://github.com/dgilman/macutils/blob/master/macunpack/cpt.c - source code
+https://github.com/MacPaw/XADMaster/wiki/CompactProSpecs - confused anti-specs
+
+Self-Extracting Archives (SEA)
+The abbreviation SEA (and extension .sea) is used for several self-extracting
+MAC archives. The Resource fork contains an executable (as indicated by
+Type="APPL") which contains the decompressor, and the Data fork contains the
+archive.
+ MAC File Type,Creator IDs = "APPL","aust" (StuffIt).
+ MAC File Type,Creator IDs = "APPL","EXTR" (CompactPro).
+ MAC File Type,Creator IDs = "APPL","DSEA" (DiskDoubler).
+There are some oddities for .sea files found in internet:
+ StuffIt .sea files: These are often raw StuffIt archives (apparently
+ somebody had removed the MacBinary header and the resource fork with
+ the decompressor).
+ CompactPro .sea files: These are often stored as MacBinary without 80h-byte
+ padding appended to the Data and Resource forks.
+ That applies to "Santa.sea" but other such files have OTHER corruptions,
+ which may include wrong Size and/or garbage in reserved MacBinary fields?
+Note: Not to be confused with ARC archives from System Enhancement Associates
+(SEA).
+
+Mac OS Data forks
+The Data fork contains the "normal data" part of the file (eg. anything like
+.TXT .DOC .GIF .JPG .WAV .ZIP .LZH .SIT .PIT .CPT etc).
+
+Mac OS Resource forks
+The Resource fork can contain executable code resources (similar to .EXE files;
+with File Type="APPL"), and various other resources (fonts, icons, text strings
+for dialog boxes, etc). Those resources are stored in filesystem-style archive
+and can be accessed with IDs and/or name strings.
+ Resource fork Header:
+ 000h 4 Offset to Resource Data section (from start of file) (100h)
+ 004h 4 Offset to Resource Map section (from start of file) (100h+DataSiz)
+ 008h 4 Size of Resource Data section (can be 0=None)
+ 00Ch 4 Size of Resource Map section
+ 010h F0h Unknown (can contain filename/type.. MAYBE just garbage padding?)
+ 100h .. Resource Data section, contains Data Record(s)
+ ... .. Resource Map section
+ Data Record(s) in Resource Data section (usually at offset 100h and up):
+ 000h 4 Size of Data for this record
+ 004h .. Data for this record
+ Resource Map section:
+ 000h 4 Offset to Resource Data section (from start of file) ;\
+ 004h 4 Offset to Resource Map section (from start of file) ; same as in
+ 008h 4 Size of Resource Data section ; header
+ 00Ch 4 Size of Resource Map section ;/
+ 010h 4 Zero (internally used by Resource Manager, nextResourceMap)
+ 014h 2 Zero (internally used by Resource Manager, fileRef)
+ 016h 2 Map Attributes
+ 0-4 Zero (reserved)
+ 5 Zero (internally used by Resource Manager, changed)
+ 6 Zero (internally used by Resource Manager, need compression)
+ 7 Resource map is read-only
+ 8-15 Zero (reserved)
+ 018h 2 Offset to Type List (from start of resource map) (usually 1Ch ?)
+ 01Ah 2 Offset to Name List (from start of resource map)
+ ... .. Type List
+ ... .. Resource List (with one or more entry for each entry in Type List)
+ ... .. Name List (each name consists of 8bit NameLength, plus name string)
+ Type List follows the header and contains an array of resource type records.
+ 000h 2 Number of Type Records, minus one (FFFFh=None, 0000h=One, etc.)
+ 002h N*8 Type Records
+ Type Record format:
+ 000h 4 Resource Type (four-character constant)
+ 004h 2 Number of Resource List entries, minus one (0000h=One, etc.)
+ 006h 2 Offset to first Resource List entry (from start of Type List)
+ Resource List entries:
+ 000h 2 Resource ID (C000h..FFFFh=Special/Owned)
+ 002h 2 Offset to Resource Name (from start of Name List) (FFFFh=None)
+ 004h 1 Attributes
+ 0 Resource data is compressed (0=No, 1=Compressed)
+ 1 Zero (internally used by Resource Manager, changed)
+ 2 Load Resource as soon as file is opened (0=No, 1=Preload)
+ 3 Resource is read-only (0=No, 1=Protected)
+ 4 Resource may not be moved in memory (0=No, 1=Locked)
+ 5 Resource may be paged out of memory (0=No, 1=Purgeable)
+ 6 Load Resource to (0=Application heap, 1=System Heap)
+ 7 Zero (reserved)
+ 005h 3 Offset to Resource Data (from start of Resource Data section)
+ 008h 4 Zero (internally used by Resource Manager, resourcePtr)
+ Note: Some (or all?) 16bit offsets are reportedly signed (max 32Kbyte), the
+ 24bit offsets are reportedly unsigned (max 16Mbyte).
+Compressed Resources (when Attributes.bit0=1)
+ Compressed resource have a standarized header, the decompression function(s)
+ are supposed to be stored in separate "dmcp" resource (unknown if the OS is
+ also providing standard decompression functions).
+ 000h 4 ID (always A89F6572h for compressed resource)
+ 004h 2 Always 0012h (maybe compression header size)
+ 006h 1 Type (0h8=Type8, 0h9=Type9)
+ 007h 1 Always 01h
+ 008h 4 Uncompressed resource size
+ 00Ch 1 For Type8: workingBufferFractionalSize ;\
+ 00Dh 1 For Type8: expansionBufferSize ; Type8
+ 00Eh 2 For Type8: dcmpID (ID in "dmcp" decompress resource) ;
+ 010h 2 For Type8: Zero (reserved?) ;/
+ 00Ch 2 For Type9: dcmpID (ID in "dmcp" decompress resource) ;\Type9
+ 00Eh 4 For Type9: decompressor_specific_parameters_with_io ;/
+ 012h .. Compressed Resource Data
+ http://formats.kaitai.io/compressed_resource/
+Owned Resources (with Resource ID=C000h..FFFFh):
+ https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format
+The upper 5bit (mask F800h) indicate the resource type of the owner, the middle
+6bit (mask 07E0h) indicate the resource id of the owner, and the lower 5bit
+(mask 001Fh) indicate the "sub-id" of the owned resource.
+ ID MSBs Owner Type Notes
+ C000h DRVR driver or desk accessory
+ C800h WDEF window definition: code to draw windows
+ D000h MDEF menu definition: code to draw menus
+ D800h CDEF control definition: code to draw UI widgets
+ E000h PDEF printer driver
+ E800h PACK utility code package/library used by the Mac OS
+ F000h cdev control panel; owner id is set to 1
+ F800h reserved reserved for future use
+The Mac OS Resource Manager used this scheme to ensure that certain types of
+programs, themselves stored in resources, could find the other resources they
+needed even if the resources had to be renumbered to avoid conflicts. Utilities
+such as Font/DA Mover that were used to install and remove these programs used
+this scheme to ensure that all associated resources were installed or removed
+as well, and renumber the resources if necessary to avoid conflicts.
+
+CDROM File XYZ and Dummy/Null Files
+-----------------------------------
+
+Dummy/Null Files
+Most PSX discs have huge zerofilled dummy files with about 32Mbytes, using
+filenames like DUMMY, NUL, NULL, or ZNULL, this is probably done to tweak the
+disc to have valid sector numbers at the end of disc (to help the drive head to
+know which sector it is on).
+Of course, Sony could as well pad the discs with longer Lead-Out areas, but the
+dummy files may have been needed during development with CDRs (though burning
+such large files doesn't exactly speed up development).
+There are different ways to make sure that the file is at end of the disc:
+- Some CDROM burning tools may allow to specify which file is where
+- Some games have the file aphabetically sorted as last file in last folder
+- Some games have the file declared as audio track
+- Some games (additionally) have large zeropadding at end of their archive file
+
+XYZ Files
+To reduce seek times, it can make sense to have the boot files & small files at
+the begin of the disc.
+Some games seem to use alphabetically sorted file/folder names to tweak Movies
+and XA-audio to be located at the end of disc (eg. using ZMOVIE as folder
+name).
+
+CDROM Protection - SCEx Strings
+-------------------------------
+
+SCEx String
+The heart of the PSX copy-protection is the four-letter "SCEx" string, encoded
+in the wobble signal of original PSX disks, which cannot reproduced by normal
+CD writers. The last letter varies depending on the region, "SCEI" for Japan,
+"SCEA" for America (and all other NTSC countries except Japan), "SCEE" for
+Europe (and all other PAL countries like Australia). If the string is missing
+(or if it doesn't match up for the local region) then the PSX refuses to boot.
+The verification is done by the Firmware inside of the CDROM Controller (not by
+the PSX BIOS, so there's no way to bypass it by patching the BIOS ROM chip).
+
+Wobble Groove and Absolute Time in Pregroove (ATIP) on CD-R's
+A "blank" CDR contains a pre-formatted spiral on it. The number of windings in
+the spiral varies depending on the number of minutes that can be recorded on
+the disk. The spiral isn't made of a straight line (------), but rather a
+wobbled line (/\/\/\), which is used to adjust the rotation speed during
+recording; at normal drive speed, wobble should produce a 22050Hz sine wave.
+Additionally, the CDR wobble is modulated to provide ATIP information, ATIP is
+used for locating and positioning during recording, and contains information
+about the approximate laser power necessary for recording, the last possible
+time location that lead out can start, and the disc application code.
+Wobble is commonly used only on (recordable) CDRs, ie. usually NOT on
+(readonly) CDROMs and Audio Disks. The copyprotected PSX CDROMs are having a
+short CDR-style wobble period in the first some seconds, which seems to contain
+the "SCEx" string instead of ATIP information.
+
+Other Protections
+Aside from the SCEx string, PSX disks are required to contain region and
+licence strings (in the ISO System Area, and in the .EXE file headers), and the
+"PS" logo (in the System Area, too). This data can be reproduced with normal CD
+writers, although it may be illegal to distribute unlicensed disks with licence
+strings.
+
+CDROM Protection - Bypassing it
+-------------------------------
+
+Modchips
+A modchip is a small microcontroller which injects the "SCEx" signal to the
+mainboard, so the PSX can be booted even from CDRs which don't contain the
+"SCEx" string. Some modchips are additionally patching region checks contained
+in the BIOS ROM.
+Note: Although regular PSX disks are black, the hardware doesn't verify the
+color of the disks, and works also with normal silver disks.
+
+Disk-Swap-Trick
+Once when the PSX has recognized a disk with the "SCEx" signal, it'll be
+satisfied until a new disk is inserted, which is sensed by the SHELL_OPEN
+switch. When having that switch blocked, it is possible to insert a CDR without
+the PSX noticing that the disk was changed.
+Additionally, the trick requires some boot software that stops the drive motor
+(so the new disk can be inserted, despite of the PSX thinking that the drive
+door is still closed), and that does then start the boot executable on the new
+disk.
+The boot software can be stored on a special boot-disk (that do have the "SCEx"
+string on it). Alternately, a regular PSX game disk could be used, with the
+boot software stored somewhere else (eg. on Expansion ROM, or BIOS ROM
+replacement, or Memory Card).
+
+Booting via BIOS ROM or Expansion ROM
+The PSX can be quite easily booted via Expansion ROM, or BIOS ROM replacements,
+allowing to execute code that is stored in the ROM, or that is received via
+whatever serial or parallel cable connection from a PC.
+However, even with a BIOS replacement, the protection in the CDROM controller
+is still active, so the ROM can't read "clean" data from the CDROM Drive
+(unless the Disk-Swap trick is used).
+Whereas, no "clean" data doens't mean no data at all. The CDROM controller does
+still seem to output "raw" data (without removing the sector header, and
+without handling error correction, and with only limited accuracy on the sector
+position). So, eventually, a customized BIOS could convert the "raw" data to
+"clean" data.
+
+Secret Unlock Commands
+There is an "official" backdoor that allows to disable the SCEx protection by
+software via secret commands (for example, sending those commands can be done
+via BIOS patches, nocash BIOS clone, or Expansion ROMs).
+--> CDROM - Secret Unlock Commands
+
+Booting via Memory Card
+Some games that load data from memory cards may get confused if the save data
+isn't formatted as how they expect it - with some fine tuning you can get them
+to "crash" in a manner that they do accidently execute bootcode stored on the
+memory card.
+Requires a tools to write to the memory card (eg. parallel port cable), and the
+memory card data customized for a specific game, and an original CDROM with
+that specific game. Once when the memory card code is booted, the Disk-Swap
+trick can be used.
+
+CDROM Protection - Modchips
+---------------------------
+
+Modchip Source Code
+The Old Crow mod chip source code works like so:
+ entrypoint: ;at power_up
+ gate=input/highz
+ data=input/highz
+ wait 50 ms
+ data=output/low
+ wait 850 ms
+ gate=output/low
+ wait 314 ms
+ loop:
+ wait 72 ms ;pause (eighteen "1=low" bits)
+ sendbyte("S") ;1st letter
+ sendbyte("C") ;2nd letter
+ sendbyte("E") ;3rd letter
+ sendbyte(...) ;4th letter (A, E, or I, depending on region)
+ goto loop
+ sendbyte(char):
+ sendbit(0) ;one start bit (0=highz)
+ for i=0 to 7
+ sendbit(char AND 1) ;output data (LSB first)
+ char=char/2
+ next i
+ sendbit(1) ;1st stop bit (1=low)
+ sendbit(1) ;2nd stop bit (1=low)
+ return
+ sendbit(bit):
+ if bit=1 then data=output/low elseif bit=0 then data=input/highz
+ wait 4 ms ;4ms per bit = 250 bits per second
+ return
+
+Connection for the data/gate/sync signals:
+For older PSX boards (data/gate):
+ Board data gate
+ PU-xx unknown? unknown? ;older PSX boards
+For newer PSX and PSone boards (data/sync):
+ Board data sync
+ PU-23, PM-41 CXD2938Q.Pin42 CXD2938Q.Pin5 ;newer PSX and older PSone
+ PM-41(2) CXD2941R.Pin36 CXD2941R.Pin76 ;newer PSone boards
+On the mainboard should be a big SMD capacitor (connected to the "data" pin),
+and a big testpoint (connected to the "sync" pin); it's easier to connect the
+signals to that locations than to the tiny CXD-chip pins.
+gate and data must be tristate outputs, or open-collector outputs (or normal
+high/low outputs passed through a diode).
+
+Note on "data" pin (all boards)
+Transfers the "SCEx" data. Note that the signal produced by the modchip is
+looking entirly different than the signal produced by original disks, the real
+signal would be modulated 22050Hz wobble, while the modchip is simply dragging
+the signal permanently LOW throughout "1" bits, and leaves it floating for "0"
+bits. Anyways the "faked" signal seems to be accurate enough to work.
+
+Note on "gate" pin (older PSX boards only)
+The "gate" pin needs to be LOW only for use with original licensed disks
+(reportedly otherwise the SCEx string on that disks would conflict with the
+SCEx string from the modchip).
+At the mainboard side, the "gate" signal is an input, and "data" is an inverted
+output of the gate signal (so dragging gate to low, would cause data to go
+high).
+
+Note on "sync" pin (newer PSX and PSone boards only)
+The "sync" pin is a testpoint on the mainboard, which does (at single speed)
+output a frequency of circa 44.1kHz/6 (of which some clock pulses seem to be
+longer or shorter, probably to indicate adjustments to the rotation speed).
+Some modchips are connected directly to "sync" (so they are apparently
+synchronizing the data output with that signal; which is not implemented in the
+above source code).
+Anyways, other modchips are using a more simplified connection: The modchip
+itself connects only to the "data" pin, and "sync" is required to be wired to
+IC723.Pin17.
+
+Note on Multi-Region chips
+Modchips that are designed to work in different regions are sending a different
+string (SCEA, SCEE, SCEI) in each loop cycle. Due to the slow 250bps transfer
+rate, it may take a while until the PSX has received the correct string, so
+this multi-region technique may cause a noticeable boot-delay.
+
+Stealth (hidden modchip)
+The Stealth connection is required for some newer games with anti-modchip
+protection, ie. games that refuse to run if they detect a modchip. The
+detection relies on the fact that the SCEx signal is normally received only
+when booting the disk, whilst older modchips were sending that signal
+permanently. Stealth modchips are sending the signal only on power-up (and when
+inserting a new disk, which can be sensed via SHELL_OPEN signal).
+Modchip detection reportedly works like so (not too sure if all commands are
+required, some seem to be rather offtopic):
+ 1. Com 19h,20h ;Retrieve CDROM Controller timestamp
+ 2. Com 01h ;CdlNop: Get CD status
+ 3. Com 07h ;CdlMotorOn: Make CD-ROM drive ready (blah?)
+ 4. Com 02h,1,1,1 ;CdlSetloc(01:01:01) (sector that does NOT have SCEx data)
+ 5. Com 0Eh,1 ;CdlSetmode: Turn on CD-DA read mode
+ 6. Short Delay
+ 7. Com 16h ;CdlSeekP: Seek to Setloc's parameters (4426)
+ 8. Com 0Bh ;CdlMute: Turn off sound so CdlPlay is inaudible
+ 9. Com 03h ;CdlPlay: Start playing CD-DA.
+ 10. Com 19h,04h ;ResetSCExInfo (reset GetSCExInfo response to 0,0)
+ 11. Long Delay ;wait until the modchip (if any) has output SCEx data
+ 12. Com 19h,05h ;GetSCExInfo (returns total,success counters)
+ 13. Com 09h ;CdlPause: Stop command 19h.
+If GetSCExInfo returns nonzero values, then the console is equipped with a
+modchip, and if so, anti-modchip games would refuse to work (no matter if the
+disk is an illegal copy, or not).
+
+NTSC-Boot BIOS Patch
+Typically connects to two or three BIOS address/data lines, apparently watching
+that signals, and dragging a data line LOW at certain time, to skip software
+based region checks (eg. allowing to play NTSC games on PAL consoles).
+Aside from the modchip connection, that additionally requires to adjust the
+video signal (in 60Hz NTSC mode, the PSX defaults to generate a NTSC video
+signal) (whilst most PAL screens can handle 60Hz refresh, they can't handle
+NTSC colors) (on PSone boards, this can be fixed simply by grounding the /PAL
+pin; IC502.Pin13) (on older PSX boards it seems to be required to install an
+external color clock generator).
+
+MODCHIP Connection Example
+Connection for 8pin "12C508" mod chip from fatcat.co.nz for a PAL PSone with
+PM-41 board (ie. with 208pin SPU CXD2938Q, and 52pin IC304 "C 3060,
+SC430943PB"):
+ 1 3.5V (supply)
+ 2 IC304.Pin44 (unknown?) (XLAT)
+ 3 BIOS.Pin15 (D2)
+ 4 BIOS.Pin31 (A18)
+ 5 SPU.Pin5 ("sync")
+ 6 SPU.Pin42 ("data")
+ 7 IC304.Pin19 (SHELL_OPEN)
+ 8 GND (supply)
+The chip can be used in a Basic connection (with only pin1,5,6,8 connected), or
+Stealth and NTSC-Boot connection (additionally pin2,3,4,7 connected). Some
+other modchips (such without internal oscillator) are additionally connected to
+a 4MHz or 4.3MHz signal on the mainboard. Some early modchips also connected to
+a bunch of additional pins that were reportedly for power-on timings (whilst
+newer chips use hardcoded power-on delays).
+
+Nocash BIOS "Modchip" Feature
+The nocash PSX bios outputs the "data" signal on the A20 address line, so
+(aside from the BIOS chip) one only needs to install a 1N4148 diode and two
+wires to unlock the CDROM:
+ SPU.Pin42 "data" -------|>|------ CPU.Pin149 (A20)
+ SPU.Pin5 "sync" ---------------- IC723.Pin17
+With the "sync" connection, the SCEx signal from the disk is disabled (ie. even
+original licensed disks are no longer recognized, unless SCEx is output via A20
+by software). For more variants, see:
+--> CDROM Protection - Chipless Modchips
+
+CDROM Protection - Chipless Modchips
+------------------------------------
+
+The nocash kernel clone outputs a SCEX signal via A20 and A21 address lines,
+(so one won't need a separate modchip/microprocessor):
+ A20 = the normal SCEX signal (inverted ASCII, eg. "A" = BEh) ;all boards
+ A21 = uninverted SCEX signal (uninverted ASCII, eg. "A" = 41h) ;PU-7..PU-20
+ A21 = always 1 during SCEX output ;PU-22 and up
+When using the clone bios as internal ROM replacement, A20 can be used with
+simple wires/diodes. Doing that with external expansion ROMs would cause the
+console to stop working when unplugging the ROM, hence needing a slightly more
+complex circuit with transistors/logic chips.
+
+External Expansion ROM version, for older boards (PU-7 through PU-20):
+ .--------.-. .--------.-.
+ GATE--------|C NPN | . DATA--------|C NPN | .
+ A20--[10K]--|B BC | | A21--[10K]--|B BC | |
+ GND---------|E 547 | ' GND---------|E 547 | '
+ '--------'-' '--------'-'
+
+External Expansion ROM version, for newer boards (PU-22):
+ .-------------------.
+ A21----|OE1,OE2 |
+ A20----|IN1 74HC126 OUT1|--- DATA
+ WFCK---|IN2 OUT2|--- SYNC
+ '-------------------'
+
+Internal Kernel ROM version, for older boards (PU-7 through PU-20):
+ GATE---------GND
+ DATA---------A20
+
+Internal Kernel ROM version, for newer boards (PU-22 through PM-41(2)):
+ SYNC--------WFCK
+ DATA---|>|---A20
+
+What pin is where...
+ GATE is IC703.Pin2 (?) (8pin chip with marking "082B") ;PU-7? .. PU-16
+ GATE is IC706.Pin7/10 (16pin "118" (uPC5023GR-118) ;PU-18 .. PU-20
+ SYNC is IC723.Pin17(TEO)(20pin "SONY CXA2575N") ;PU-22 .. PM-41(2)
+ DATA is IC???.Pin7 (CG) (8pin chip with marking "2903") ;PU-7? .. PU-16
+ DATA is IC706.Pin1 (CG) (16pin "118" (uPC5023GR-118) ;PU-18 .. PU-20
+ DATA is HC05.Pin17 (CG) (52pin "SONY SC4309xxPB") ;PU-7 .. EARLY-PU-8
+ DATA is HC05.Pin32 (CG) (80pin "SONY E35D, 4246xx 185") ;LATE-PU-8 .. PU-20
+ DATA is SPU.Pin42 (CEI) (208pin "SONY CXD2938Q") ;PU-22 .. PM-41
+ DATA is SPU.Pin36?(CEI) (176pin "SONY CXD2941R") ;PM-41(2)
+ WFCK is SPU.Pin5 (WFCK) (208pin "SONY CXD2938Q") ;PU-22 .. PM-41
+ WFCK is SPU.Pin84(WFCK) (176pin "SONY CXD2941R") ;PM-41(2)
+ A20 is CPU.Pin149(A20) (208-pin CPU CXD8530 or CXD8606) ;PU-7 .. PM-41(2)
+ A20 is EXP.Pin28 (A20) (68-pin Expansion Port) ;PU-7 .. PU-22
+ A21 is CPU.Pin150(A21) (208-pin CPU CXD8530 or CXD8606) ;PU-7 .. PM-41(2)
+ A21 is EXP.Pin62 (A21) (68-pin Expansion Port) ;PU-7 .. PU-22
+GATE on PU-18 is usually IC706.Pin7 (but IC706.Pin10 reportedly works, too).
+GATE on PU-20 is usually IC706.Pin10 (but IC706.Pin7 might work, too).
+
+CDROM Protection - LibCrypt
+---------------------------
+
+LibCrypt is an additional copy-protection, used by about 100 PSX games. The
+protection uses a 16bit decryption key, which is stored as bad position data in
+Subchannel Q. The 16bit key is then used for a simple XOR-decryption on certain
+800h-byte sectors.
+
+Protected sectors generation schemas
+There are some variants on how the Subchannel Q data is modified:
+ 1. 2 bits from both MSFs are modified,
+ CRC-16 is recalculated and XORed with 0x0080.
+ Games: MediEvil (E).
+ 2. 2 bits from both MSFs are modified,
+ original CRC-16 is XORed with 0x8001.
+ Games: CTR: Crash Team Racing (E) (No EDC), CTR: Crash Team Racing (E)
+ (EDC), Dino Crisis (E), Eagle One: Harrier Attack (E) et al.
+ 3. Either 2 bits or none from both MSFs are modified,
+ CRC-16 is recalculated and XORed with 0x0080.
+ Games: Ape Escape (S) et al.
+Anyways, the relevant part is that the modified sectors have wrong CRCs (which
+means that the PSX cdrom controller will ignore them, and the GetlocP command
+will keep returning position data from the previous sector).
+
+LibCrypt sectors
+The modified sectors could be theoretically located anywhere on the disc,
+however, all known protected games are having them located on the same sectors:
+ No. <------- Minute=03/Normal -------> <------- Minute=09/Backup ------->
+ Bit15 14105 (03:08:05) 14110 (03:08:10) 42045 (09:20:45) 42050 (09:20:50)
+ Bit14 14231 (03:09:56) 14236 (03:09:61) 42166 (09:22:16) 42171 (09:22:21)
+ Bit13 14485 (03:13:10) 14490 (03:13:15) 42432 (09:25:57) 42437 (09:25:62)
+ Bit12 14579 (03:14:29) 14584 (03:14:34) 42580 (09:27:55) 42585 (09:27:60)
+ Bit11 14649 (03:15:24) 14654 (03:15:29) 42671 (09:28:71) 42676 (09:29:01)
+ Bit10 14899 (03:18:49) 14904 (03:18:54) 42813 (09:30:63) 42818 (09:30:68)
+ Bit9 15056 (03:20:56) 15061 (03:20:61) 43012 (09:33:37) 43017 (09:33:42)
+ Bit8 15130 (03:21:55) 15135 (03:21:60) 43177 (09:35:52) 43182 (09:35:57)
+ Bit7 15242 (03:23:17) 15247 (03:23:22) 43289 (09:37:14) 43294 (09:37:19)
+ Bit6 15312 (03:24:12) 15317 (03:24:17) 43354 (09:38:04) 43359 (09:38:09)
+ Bit5 15378 (03:25:03) 15383 (03:25:08) 43408 (09:38:58) 43413 (09:38:63)
+ Bit4 15628 (03:28:28) 15633 (03:28:33) 43634 (09:41:59) 43639 (09:41:64)
+ Bit3 15919 (03:32:19) 15924 (03:32:24) 43963 (09:46:13) 43968 (09:46:18)
+ Bit2 16031 (03:33:56) 16036 (03:33:61) 44054 (09:47:29) 44059 (09:47:34)
+ Bit1 16101 (03:34:51) 16106 (03:34:56) 44159 (09:48:59) 44164 (09:48:64)
+ Bit0 16167 (03:35:42) 16172 (03:35:47) 44312 (09:50:62) 44317 (09:50:67)
+Each bit is stored twice on Minute=03 (five sectors apart). For some reason,
+there is also a "backup copy" on Minute=09 (however, the libcrypt software
+doesn't actually support using that backup stuff, and, some discs don't have
+the backup at all (namely, discs with less than 10 minutes on track 1?)).
+A modified sector means a "1" bit, an unmodified means a "0" bit. The 16bit
+keys of the existing games are always having eight "0" bits, and eight "1" bits
+(meaning that there are 16 modified sectors on Minute=03, and, if present,
+another 16 ones one Minute=09).
+
+Example (Legacy of Kain)
+Legacy of Kain (PAL) is reading the LibCrypt data during the title screen, and
+does then display GOT KEY!!! on TTY terminal (this, no matter if the correct
+16bit key was received).
+The actual protection jumps in a bit later (shortly after learning to glide,
+the game will hang when the first enemies appear if the key isn't okay).
+Thereafter, the 16bit key is kept used once and when to decrypt 800h-byte
+sector data via simple XORing.
+The 16bit key (and some other related counters/variables) aren't stored in RAM,
+but rather in COP0 debug registers (which are mis-used as general-purpose
+storage in this case), for example, the 16bit key is stored in LSBs of the
+"cop0r3" register.
+In particuar, the encryption is used for some of the BIGFILE.DAT folder
+headers:
+--> CDROM File Archive BIGFILE.DAT (Soul Reaver)
+
+CDROM Disk Images CCD/IMG/SUB (CloneCD)
+---------------------------------------
+
+File.IMG - 2352 (930h) bytes per sector
+Contains the sector data, recorded at 930h bytes per sector. Unknown if other
+sizes are also used/supported (like 800h bytes/sector, or even images with
+mixed sizes of 800h and 930h for different tracks).
+
+File.SUB - 96 (60h) bytes per sector (subchannel P..W with 96 bits each)
+Contains subchannel data, recorded at 60h bytes per sector.
+ 00h..0Bh 12 Subchannel P (Pause-bits, usually all set, or all cleared)
+ 0Ch..17h 12 Subchannel Q (ADR/Control, custom info, CRC-16-CCITT)
+ 18h..5Fh .. Subchannel R..W (usually zero) (can be used for CD-TEXT)
+Optionally, the .SUB file can be omitted (it's needed only for discs with
+non-standard subchannel data, such like copy-protected games).
+
+File.CCD - Lead-in info in text format
+Contains Lead-in info in ASCII text format. Lines should be terminated by
+0Dh,0Ah. The overall CCD filestructure is:
+ [CloneCD] ;File ID and version
+ [Disc] ;Overall Disc info
+ [CDText] ;CD-TEXT (included only if present)
+ [Session N] ;Session(s) (numbered 1 and up)
+ [Entry N] ;Lead-in entries (numbered 0..."TocEntries-1")
+ [TRACK N] ;Track info (numbered 1 and up)
+Read on below for details on the separate sections.
+
+[CloneCD]
+ Version=3 ;-version (usually 3) (rarely 2)
+
+[Disc]
+ TocEntries=4 ;-number of [Entry N] fields (lead-in info blocks)
+ Sessions=1 ;-number of sessions (usually 1)
+ DataTracksScrambled=0 ;-unknown purpose (usually 0)
+ CDTextLength=0 ;-total size of 18-byte CD-TEXT chunks (usually 0)
+ CATALOG=NNNNNNNNNNNNN ;-13-digit EAN-13 barcode (included only if present)
+
+[CDText]
+ Entries=N ;number of following entries (CDTextLength/18) (not /16)
+ Entry 0=80 00 NN NN NN NN NN NN NN NN NN NN NN NN NN NN ;entry 0
+ Entry 1=80 NN NN NN NN NN NN NN NN NN NN NN NN NN NN NN ;entry 1
+ ...
+ Entry XX=8f NN NN NN NN NN NN NN NN NN NN NN NN NN NN NN ;entry N-1
+ Note: Each entry contains 16 bytes (ie. "18-byte CD-TEXT" with CRC excluded)
+ "NN NN NN.." consists of 2-digit lowercase HEX numbers (without leading "0x")
+
+[Session 1]
+ PreGapMode=2 ;-unknown purpose (usually 1 or 2)
+ PreGapSubC=1 ;-unknown purpose (usually 0 or 1)
+
+[Entry 0]
+[Entry 0..2] are usually containing Point A0h..A2h info. [Entry 3..N] are
+usually TOC info for Track 1 and up.
+ Session=1 ;-session number that this entry belongs to (usually 1)
+ Point=0xa0 ;-point (0..63h=Track, non-BCD!) (A0h..XXh=specials) Q2
+ ADR=0x01 ;-lower 4bit of ADR/Control (usually 1) Q0.lo
+ Control=0x04 ;-upper 4bit of ADR/Control (eg. 0=audio, 4=data) Q0.hi
+ TrackNo=0 ;-usually/always 0 (as [Entry N]'s are in Lead-in) Q1
+ AMin=0 ;\current MSF address Q3
+ ASec=0 ; (dummy zero values) (actual content Q4
+ AFrame=0 ; would be current lead-in position) Q5
+ ALBA=-150 ;/ALBA=((AMin*60+ASec)*75+AFrame)-PreGapSize
+ Zero=0 ;-probably reserved byte from Q channel Q6
+ PMin=1 ;\referenced MSF address (non-BCD!), for certain Q7
+ PSec=32 ; Point's, PMin may contain a Track number, and PSec Q8
+ PFrame=0 ; the disc type value (that without non-BCD-glitch) Q9
+ PLBA=6750 ;/PLBA=((PMin*60+PSec)*75+PFrame)-PreGapSize
+
+[TRACK 1] ;-track number (non-BCD) (1..99)
+ MODE=2 ;-mode (0=Audio, 1=Mode1, 2=Mode2)
+ ISRC=XXXXXNNNNNNN ;-12-letter/digit ISRC code (included only if present)
+ INDEX 0=N ;-1st sector with index 0, missing EVEN if any?
+ INDEX 1=N ;-1st sector with index 1, usually same as track's PLBA
+ INDEX 2=N ;-1st sector with index 2, if any
+ etc.
+
+Missing Sectors & Sector Size
+The .CCD file doesn't define the "PreGapSize" (the number of missing sectors at
+begin of first track). It seems to be simply constant " PreGapSize=150". Unless
+one is supposed to calculate it as
+"PreGapSize=((PMin*60+PSec)*75+PFrame)-PLBA".
+The SectorSize seems to be also constant, "SectorSize=930h".
+
+Non-BCD Caution
+All Min/Sec/Frame/Track/Index values are expressed in non-BCD, ie. they must be
+converted to BCD to get the correct values (as how they are stored on real
+CDs). Exceptions are cases where those bytes have other meanings: For example,
+"PSec=32" does normally mean BcdSecond=32h, but for Point A0h it would mean
+DiscType=20h=CD-ROM-XA).
+The Point value is also special, it is expressed in hex (0xNN), but nonetheless
+it is non-BCD, ie. Point 1..99 are specified as 0x01..0x63, whilst, Point
+A0h..FFh are specified as such (ie. as 0xA0..0xFF).
+
+Versions
+Version=1 doesn't seem to exist (or it is very rare). Version=2 is quite rare,
+and it seems to lack the [TRACK N] entries (meaning that there is no MODE and
+INDEX information, except that the INDEX 1 location can be assumed to be same
+as PLBA). Version=3 is most common, this version includes [TRACK N] entries,
+but often only with INDEX=1 (and up, if more indices), but without INDEX 0 (on
+Track 1 it's probably missing due to pregap, on further Tracks it's missing
+without reason) (so, only ways to reproduce INDEX=0 would be to guess it being
+located 2 seconds before INDEX=1, or, to use the information from the separate
+.SUB file, if that file is present; note: presence of index 0 is absolutely
+required for some games like PSX Tomb Raider 2).
+
+Entry & Points & Sessions
+The [Entry N] fields are usually containing Point A0h,A1h,A2h, followed by
+Point 1..N (for N tracks). For multiple sessions: The session is terminated by
+Point B0h,C0h. The next session does then contain Point A0h,A1h,A2h, and Point
+N+1..X (for further tracks). The INDEX values in the [TRACK N] entries are
+originated at the begin of the corresponding session, whilst PLBA values in
+[Entry N] entries are always originated at the begin of the disk.
+
+CDROM Disk Images CDI (DiscJuggler)
+-----------------------------------
+
+Overall Format
+ Sector Data (sector 00:00:00 and up) ;-body
+ Number of Sessions (1 byte) <--- located at "Filesize-Footersize"
+ Session Block for 1st session (15 bytes) ;\
+ nnn-byte info for 1st track ; 1st session
+ nnn-byte info for 2nd track (if any) ;
+ etc. ;/
+ Session Block for 2nd session (15 bytes) ;\
+ nnn-byte info for 1st track ; 2nd session (if any)
+ nnn-byte info for 2nd track (if any) ;
+ etc. ;/
+ etc. ;-further sessions (if any)
+ Session Block for no-more-sessions (15 bytes) ;-end marker
+ nnn-byte Disc Info Block ;-general disc info
+ Entrypoint (4 bytes) <--- located at "Filesize-4"
+
+Sector Data
+Contains Sector Data for sector 00:00:00 and up (ie. all sectors are stored in
+the file, there are no missing "pregap" sectors).
+Sector Size can be 800h..990h bytes/sector (sector size may vary per track).
+
+Number of Sessions (1 byte)
+ 00h 1 Number of Sessions (usually 1)
+
+Session Block (15-bytes)
+ 00h 1 Unknown (00h)
+ 01h 1 Number of Tracks in session (01h..63h) (or 00h=No More Sessions)
+ 02h 7 Unknown (00h-filled)
+ 09h 1 Unknown (01h)
+ 0Ah 3 Unknown (00h-filled)
+ 0Dh 2 Unknown (FFh,FFh)
+
+Track/Disc Header (30h+F bytes) (used in Track Blocks and Disc Info Block)
+ 00h 12 Unknown (FFh,FFh,00h,00h,01h,00h,00h,00h,FFh,FFh,FFh,FFh)
+ 0Ch 3 Unknown (DAh,0Ah,D5h or 64h,05h,2Ah) (random/id/chksum?)
+ 0Fh 1 Total Number of Tracks on Disc (00h..63h) (non-BCD)
+ 10h 1 Length of below Path/Filename (F)
+ 11h (F) Full Path/Filename (eg. "C:\folder\file.cdi")
+ 11h+F 11 Unknown (00h-filled)
+ 1Ch+F 1 Unknown (02h)
+ 1Dh+F 10 Unknown (00h-filled)
+ 27h+F 1 Unknown (80h)
+ 28h+F 4 Unknown (00057E40h) (=360000 decimal) (disc capacity 80 minutes?)
+ 2Ch+F 2 Unknown (00h,00h)
+ 2Eh+F 2 Medium Type (0098h=CD-ROM, 0038h=DVD-ROM)
+
+Track Block (E4h+F+I+T bytes)
+ 00h 30h+F Track/Disc Header (see above)
+ 30h+F 02h Number of Indices (usually 0002h) (I=Num*4)
+ 32h+F (I) 32bit Lengths (per index) (eg. 00000096h,00007044h)
+ 32h+FI 04h Number of CD-Text blocks (usually 0) (T=Num*18+VariableLen's)
+ 36h+FI (T) CD-Text (if any) (see "mirage_parser_cdi_parse_cdtext")
+ 36h+FIT 02h Unknown (00h,00h)
+ 38h+FIT 01h Track Mode (0=Audio, 1=Mode1, 2=Mode2/Mixed)
+ 39h+FIT 07h Unknown (00h,00h,00h,00h,00h,00h,00h)
+ 40h+FIT 04h Session Number (starting at 0) (usually 00h)
+ 44h+FIT 04h Track Number (non-BCD, starting at 0) (00h..62h)
+ 48h+FIT 04h Track Start Address (eg. 00000000h)
+ 4Ch+FIT 04h Track Length (eg. 000070DAh)
+ 50h+FIT 0Ch Unknown (00h-filled)
+ 5Ch+FIT 04h Unknown (00000000h or 00000001h)
+ 60h+FIT 04h read_mode (0..4)
+ 0: Mode1, 800h, 2048
+ 1: Mode2, 920h, 2336
+ 2: Audio, 930h, 2352
+ 3: Raw+PQ, 940h, 2352+16 non-interleaved (P=only 1bit)
+ 4: Raw+PQRSTUVW, 990h, 2352+96 interleaved
+ 64h+FIT 4 Control (Upper 4bit of ADR/Control, eg. 00000004h=Data)
+ 68h+FIT 1 Unknown (00h)
+ 69h+FIT 4 Track Length (eg. 000070DAh) (same as above)
+ 6Dh+FIT 4 Unknown (00h,00h,00h,00h)
+ 71h+FIT 12 ISRC Code 12-letter/digit (ASCII?) string (00h-filled if none)
+ 7Dh+FIT 4 ISRC Valid Flag (0=None, Other?=Yes?)
+ 81h+FIT 1 Unknown (00h)
+ 82h+FIT 8 Unknown (FFh,FFh,FFh,FFh,FFh,FFh,FFh,FFh)
+ 8Ah+FIT 4 Unknown (00000001h)
+ 8Eh+FIT 4 Unknown (00000080h)
+ 92h+FIT 4 Unknown (00000002h) (guess: maybe audio num channels??)
+ 96h+FIT 4 Unknown (00000010h) (guess: maybe audio bits/sample??)
+ 9Ah+FIT 4 Unknown (0000AC44h) (44100 decimal, ie. audio sample rate?)
+ 9Eh+FIT 2Ah Unknown (00h-filled)
+ C8h+FIT 4 Unknown (FFh,FFh,FFh,FFh)
+ CCh+FIT 12 Unknown (00h-filled)
+ D8h+FIT 1 session_type ONLY if last track of a session (else 0)
+ (0=Audio/CD-DA, 1=Mode1/CD-ROM, 2=Mode2/CD-XA)
+ D9h+FIT 5 Unknown (00h-filled)
+ DEh+FIT 1 Not Last Track of Session Flag (0=Last Track, 1=Not Last)
+ DFh+FIT 1 Unknown (00h)
+ E0h+FIT 4 address for last track of a session? (otherwise 00,00,FF,FF)
+
+Disc Info Block (5Fh+F+V+T bytes)
+ 00h 30h+F Track/Disc Header (see above)
+ 30h+F 4 Disc Size (total number of sectors)
+ 34h+F 1 Volume ID Length (V) ;\from Primary Volume Descriptor[28h..47h]
+ 35h+F (V) Volume ID String ;/(ISO Data discs) (unknown for Audio)
+ 35h+FV 1 Unknown (00h)
+ 36h+FV 4 Unknown (01h,00h,00h,00h)
+ 3Ah+FV 4 Unknown (01h,00h,00h,00h)
+ 3Eh+FV 13 EAN-13 Code 13-digit (ASCII?) string (00h-filled if none)
+ 4Bh+FV 4 EAN-13 Valid Flag (0=None, Other?=Yes?)
+ 4Fh+FV 4 CD-Text Length in bytes (T=Num*1)
+ 53h+FV (T) CD-Text (for Lead-in) (probably 18-byte units?)
+ 53h+FVT 8 Unknown (00h-filled)
+ 5Bh+FVT 4 Unknown (06h,00h,00h,80h)
+
+Entrypoint (4 bytes) (located at "Filesize-4")
+ 00h 4 Footer Size in bytes
+
+CDROM Disk Images CUE/BIN/CDT (Cdrwin)
+--------------------------------------
+
+.CUE/.BIN (CDRWIN)
+CDRWIN stores disk images in two separate files. The .BIN file contains the raw
+disk image, starting at sector 00:02:00, with 930h bytes per sector, but
+without any TOC or subchannel information. The .CUE file contains additional
+information about the separate track(s) on the disk, in ASCII format, for
+example:
+ FILE "PATH\FILENAME.BIN" BINARY
+ TRACK 01 MODE2/2352
+ INDEX 01 00:00:00 ;real address = 00:02:00 (+2 seconds)
+ TRACK 02 AUDIO
+ PREGAP 00:02:00 ;two missing seconds (NOT stored in .BIN)
+ INDEX 01 08:09:29 ;real address = 08:13:29 (+2 seconds +pregap)
+ TRACK 03 AUDIO
+ INDEX 00 14:00:29 ;real address = 14:04:29 (+2 seconds +pregap)
+ INDEX 01 14:02:29 ;real address = 14:06:29 (+2 seconds +pregap)
+ TRACK 04 AUDIO
+ INDEX 00 18:30:20 ;real address = 18:34:20 (+2 seconds +pregap)
+ INDEX 01 18:32:20 ;real address = 18:36:20 (+2 seconds +pregap)
+The .BIN file does not contain ALL sectors, as said above, the first 2 seconds
+are not stored in the .BIN file. Moreover, there may be missing sectors
+somewhere in the middle of the file (indicated as PREGAP in the .CUE file;
+PREGAPs are usually found between Data and Audio Tracks).
+The MM:SS:FF values in the .CUE file are logical addresses in the .BIN file,
+rather than physical addresses on real CDROMs. To convert the .CUE values back
+to real addresses, add 2 seconds to all MM:SS:FF addresses (to compensate the
+missing first 2 seconds), and, if the .CUE contains a PREGAP, then the pregap
+value must be additionally added to all following MM:SS:FF addresses.
+The end address of the last track is not stored in the .CUE, instead, it can be
+only calculated by converting the .BIN filesize to MM:SS:FF format and adding 2
+seconds (plus any PREGAP values) to it.
+
+FILE <filename> BINARY|MOTOTOLA..or..MOTOROLA?|AIFF|WAVE|MP3
+ (must appear before any other commands, except CATALOG)
+ (uh, may also appear before further tracks)
+
+FLAGS DCP 4CH PRE SCMS
+
+INDEX NN MM:SS:FF
+
+TRACK NN datatype
+ AUDIO ;930h ;bytes 000h..92Fh
+ CDG ;? ;?
+ MODE1/2048 ;800h ;bytes 010h..80Fh
+ MODE1/2352 ;930h ;bytes 000h..92Fh
+ MODE2/2336 ;920h ;bytes 010h..92Fh
+ MODE2/2352 ;930h ;bytes 000h..92Fh
+ CDI/2336 ;920h ;?
+ CDI/2352 ;930h ;bytes 000h..92Fh
+
+PREGAP MM:SS:FF
+POSTGAP MM:SS:FF
+Duration of silence at the begin (PREGAP) or end (POSTGAP) of a track. Even if
+it isn't specified, the first track will always have a 2-second pregap.
+The gaps are NOT stored in the BIN file.
+
+REM comment
+Allows to insert comments/remarks (which are usually ignored). Some third-party
+tools are mis-using REM to define additional information.
+
+CATALOG 1234567890123
+ISRC ABCDE1234567
+ (ISRC must be after TRACK, and before INDEX)
+
+PERFORMER "The Band"
+SONGWRITER "The Writer"
+TITLE "The Title"
+These entries allow to define basic CD-Text info directly in the .CUE file.
+Some third-party utilites allow to define additional CD-Text info via REM
+lines, eg. "REM GENRE Rock".
+Alternately, more complex CD-Text data can be stored in a separate .CDT file.
+
+CDTEXTFILE "C:\LONG FILENAME.CDT"
+Specifies an optional file which may contain CD-TEXT. The .CDT file consists of
+raw 18-byte CD-TEXT fragments (which may include any type of information,
+including exotic one's like a "Message" from the producer). For whatever
+reason, there's a 00h-byte appended at the end of the file. Alternately to the
+.CDT file, the less exotic types of CD-TEXT can be defined by PERFORMER, TITLE,
+and SONGWRITER commands in the .CUE file.
+
+Missing
+Unknown if newer CUE/BIN versions do also support subchannel data.
+
+Malformed .CUE files
+Some .CCD files are bundled with uncommon/corrupted .CUE files, with entries as
+so:
+ TRACK 1 MODE2/2352 ;three spaces indent, and 1-digit track
+ INDEX 1 00:00:00 ;three spaces indent, and 1-digit index
+Normally, that should look as so:
+ TRACK 01 MODE2/2352 ;two spaces indent, and 2-digit track
+ INDEX 01 00:00:00 ;four spaces indent, and 2-digit index
+The purpose of the malformed .CUE might be unsuccessful compatibility, or
+tricking people into thinking that .CCD works better than .CUE.
+
+CDROM Disk Images MDS/MDF (Alcohol 120%)
+----------------------------------------
+
+File.MDF - Contains sector data (optionally with sub-channel data)
+Contains the sector data, recorded at 800h..930h bytes per sector, optionally
+followed by 60h bytes subchannel data (appended at the end of each sector). The
+stuff seems to be start on 00:02:00 (ie. the first 150 sectors are missing; at
+least it is like so when "Session Start Sector" is -150).
+The subchannel data (if present) consists of 8 subchannels, stored in 96 bytes
+(each byte containing one bit per subchannel).
+ Bit7..0 = Subchannel P..W (in that order, eg. Bit6=Subchannel Q)
+The 96 bits (per subchannel) can be translated to bytes, as so:
+ 1st..8th bit = Bit7..Bit0 of 1st byte (in that order, ie. MSB/Bit7 first)
+ 9st..16th bit = Bit7..Bit0 of 2nd byte ("")
+ 17th.. = etc.
+
+File.MDS - Contains disc/lead-in info (in binary format)
+An MDS file's structure consists of the following stuff ...
+ Header (58h bytes)
+ Session block(s) (usually one 18h byte entry)
+ Data blocks (N*50h bytes)
+ Index blocks (usually N*8 bytes)
+ Filename blocks(s) (usually one 10h byte entry)
+ Filename string(s) (usually one 6 byte string)
+
+Header (58h bytes)
+ 00h 16 File ID ("MEDIA DESCRIPTOR")
+ 10h 2 Unknown (01h,03h or 01h,04h or 01h,05h) (Fileformat version?)
+ 12h 2 Media Type (0=CD-ROM, 1=CD-R, 2=CD-RW, 10h=DVD-ROM, 12h=DCD-R)
+ 14h 2 Number of sessions (usually 1)
+ 16h 4 Unknown (02h,00h,00h,00h)
+ 1Ah 2 Zero (for DVD: Length of BCA data)
+ 1Ch 8 Zero
+ 24h 4 Zero (for DVD: Offset to BCA data)
+ 28h 18h Zero
+ 40h 4 Zero (for DVD: Offset to Disc Structures) (from begin of .MDS file)
+ 44h 0Ch Zero
+ 50h 4 Offset to First Session-Block (usually 58h) (from begin of .MDS file)
+ 54h 4 Zero (for DVD?: Offset to DPM data blocks) (from begin of .MDS file)
+
+Session-Blocks (18h bytes)
+ 00h 4 Session Start Sector (starting at FFFFFF6Ah=-150 in first session)
+ 04h 4 Session End Sector (XXX plus 150 ?)
+ 08h 2 Session number (starting at 1) (non-BCD)
+ 0Ah 1 Number of Data Blocks with any Point value (Total Data Blocks)
+ 0Bh 1 Number of Data Blocks with Point>=A0h (Special Lead-In info)
+ 0Ch 2 First Track Number in Session (01h..63h, non-BCD!)
+ 0Eh 2 Last Track Number in Session (01h..63h, non-BCD!)
+ 10h 4 Zero
+ 14h 4 Offset to First Data-Block (usually 70h) (from begin of .MDS file)
+
+Data-Blocks (50h bytes)
+Block 0..2 are usually containing Point A0h..A2h info. Block 3..N are usually
+TOC info for Track 1 and up.
+ 00h 1 Track mode (see below for details)
+ 01h 1 Number of subchannels in .MDF file (0=None, 8=Sector has +60h bytes)
+ 02h 1 ADR/Control (but with upper/lower 4bit swapped, ie. MSBs=ADR!) Q0
+ 03h 1 TrackNo (usually/always 00h; as this info is in Lead-in area) Q1
+ 04h 1 Point (Track 01h..63h, non-BCD!) (or A0h and up=Lead-in info) Q2
+ 05h 4 Zero (probably dummy MSF and reserved byte from Q channel) Q3..Q6?
+ 09h 1 Minute (Non-BCD!) (if track >= 0xA0 -> info about track ###) Q7
+ (if track = 0xA2 -> min. @ lead-out)
+ 0Ah 1 Second (Non-BCD!) (if track = 0xA2 -> sec. @ lead-out) Q8
+ 0Bh 1 Frame (Non-BCD!) (if track = 0xA2 -> frame @ lead-out) Q9
+For Point>=A0h, below 44h bytes at [0Ch..4Fh] are zero-filled
+ 0Ch 4 Offset to Index-block for this track (from begin of .MDS file)
+ 10h 2 Sector size (800h..930h) (or 860h..990h if with subchannels)
+ 12h 1 Unknown (02h) (maybe number of indices?)
+ 13h 11h Zero
+ 24h 4 Track start sector, PLBA (00000000h=00:02:00)
+ 28h 8 Track start offset (from begin of .MDF file)
+ 30h 4 Number of Filenames for this track (usually 1)
+ 34h 4 Offset to Filename Block for this track (from begin of .MDS file)
+ 38h 18h Zero
+Trackmode:
+ (upper 4bit seem to be meaningless?)
+ 00h=None (used for entries with Point=A0h..FF)
+ A9h=AUDIO ;sector size = 2352 930h ;bytes 000h..92Fh
+ AAh=MODE1 ;sector size = 2048 800h ;bytes 010h..80Fh
+ ABh=MODE2 ;sector size = 2336 920h ;bytes 010h..92Fh
+ ACh=MODE2_FORM1 ;sector size = 2048 800h ;bytes 018h..817h (incomplete!)
+ ADh=MODE2_FORM2 ;sector size = 2324+0? 914h ;bytes 018h..91Bh (incomplete!)
+ ADh=MODE2_FORM2 ;sector size = 2324+4? 918h ;bytes ??..?? (contains what?)
+ ECh=MODE2 ;sector size = 2448 990h ;(930h+60h) (with subchannels)
+
+Index Blocks (usually 8 bytes per track)
+ 00h 4 Number of sectors with Index 0 (usually 96h or zero)
+ 04h 4 Number of sectors with Index 1 (usually size of main-track area)
+Index blocks are usually 8 bytes in size (two indices per track). Maybe this
+block is/was intended to allow to contain more indices (although the Alcohol
+120% does always store only 2 indices, even when recording a CD with more than
+2 indices per track).
+The MDS file does usually contain Index blocks for <all> Data Blocks (ie.
+including unused dummy Index Blocks for Data Blocks with Point>=A0h).
+
+Filename Blocks (10h bytes)
+ 00h 4 Offset to Filename (from begin of .MDS file)
+ 04h 1 Filename format (0=8bit, 1=16bit characters)
+ 05h 11 Zero
+Normally all tracks are sharing the same filename block (although theoretically
+the tracks could use separate filename blocks; with different filenames).
+
+Filename Strings (usually 6 bytes)
+ 00h 6 Filename, terminated by zero (usually "*.mdf",00h)
+Contains the filename of the of the sector data (usually "*.mdf", indicating to
+use the same name as for the .mds file, but with .mdf extension).
+
+Missing
+Unknown if/how this format supports EAN-13, ISRC, CD-TEXT.
+Unknown if Track/Point/Index are BCD or non-BCD.
+
+CDROM Disk Images NRG (Nero)
+----------------------------
+
+.NRG (NERO)
+Nero is probably the most bloated and most popular CD recording software. The
+first part of the file contains the disk image, starting at sector 00:00:00,
+with 800h..930h bytes per sector. Additional chunk-based information is
+appended at the end of the file, usually consisting of only four chunks:
+CUES,DAOI,END!,NERO (in that order).
+
+Chunk Entrypoint (in last 8/12 bytes of file)
+ 4 File ID "NERO"/"NER5"
+ 4/8 Fileoffset of first chunk
+
+Cue Sheet (summary of the Table of Contents, TOC)
+ 4 Chunk ID "CUES"/"CUEX"
+ 4 Chunk size (bytes)
+below EIGHT bytes repeated for each track/index,
+of which, first FOUR bytes are same for both CUES and CUEX,
+ 1 ADR/Control from TOC (usually LSBs=ADR=1=fixed, MSBs=Control=Variable)
+ 1 Track (BCD) (00h=Lead-in, 01h..99h=Track N, AAh=Lead-out)
+ 1 Index (BCD) (usually 00h=pregap, 01h=actual track)
+ 1 Zero
+next FOUR bytes for CUES,
+ 1 Zero
+ 1 Minute (BCD) ;starting at 00:00:00 = 2 seconds before ISO vol. descr.
+ 1 Second (BCD)
+ 1 Sector (BCD)
+or, next FOUR four bytes for CUEX,
+ 4 Logical Sector Number (HEX) ;starting at FFFFFF6Ah (=00:00:00)
+Caution: Above may contain two position 00:00:00 entries: one nonsense entry
+for Track 00 (lead-in), followed by a reasonable entry for Track 01, Index 00.
+
+Disc at Once Information
+ 4 Chunk ID "DAOI"/"DAOX"
+ 4 Chunk size (bytes)
+ 4 Garbage (usually same as above Chunk size)
+ 13 EAN-13 Catalog Number (13-digit ASCII) (or 00h-filled if none/unknown)
+ 1 Zero
+ 1 Disk type (00h=Mode1 or Audio, 20h=XA/Mode2) (and probably 10h=CD-I?)
+ 1 Unknown (01h)
+ 1 First track (Non-BCD) (01h..63h)
+ 1 Last track (Non-BCD) (01h..63h)
+below repeated for each track,
+ 12 ISRC in ASCII (eg. "USXYZ9912345") (or 00h-filled if none/unknown)
+ 2 Sector size (usually 800h, 920h, or 930h) (see Mode entry for more info)
+ 1 Mode:
+ 0=Mode1/800h ;raw mode1 data (excluding sync+header+edc+errorinfo)
+ 3=Mode2/920h ;almost full sector (exluding first 16 bytes; sync+header)
+ 6=Mode2/930h ;full sector (including first 16 bytes; sync+header)
+ 7=Audio/930h ;full sector (plain audio data)
+ Mode values from wikipedia:
+ 00h for data Mode1/800h
+ 02h
+ 03h for Mode 2 Form 1 data eh? FORM1??? Mode2/920h
+ 05h for raw data Mode1?/930h
+ 06h for raw Mode 2/form 1 data Mode2/930h
+ 07h for audio Audio/930h
+ 0Fh for raw data with sub-channel Mode1?/930h+WHAT?
+ 10h for audio with sub-channel Audio/930h+WHAT?
+ 11h for raw Mode 2/form 1 data with sub-channel Mode2/WHAT?+WHAT?
+ Note: Some newer files do actually use different sector sizes for each
+ track (eg. 920h for the data track, and 930h for any following audio
+ tracks), older files were using the same sector size for all tracks
+ (eg. if the disk contained 930-byte Audio tracks, then Data tracks
+ were stored at the same size, rather than at 800h or 920h bytes).
+ 3 Unknown (always 00h,00h,01h)
+ 4/8 Fileoffset 1 (Start of Track's Pregap) (with Index=00h)
+ 4/8 Fileoffset 2 (Start of actual Track) (with Index=01h and up)
+ 4/8 Fileoffset 3 (End of Track+1) (aka begin of next track's pregap)
+
+End of chain
+ 4 Chunk ID "END!"
+ 4 Chunk size (always zero)
+
+Track Information (contained only in Track at Once images)
+ 4 Chunk ID "TINF"/"ETNF"/"ETN2"
+ 4 Chunk size (bytes)
+below repeated for each track,
+ 4/4/8 Track fileoffset ;\32bit in TINF/ETNF chunks,
+ 4/4/8 Track length (bytes) ;/64bit in ETN2 chunks
+ 4 Mode (should be same as in DAO chunks, see there) (implies sector size)
+ 0/4/4 Start lba on disc ;\only in ETNF/ETN2 chunks,
+ 0/4/4 Unknown? ;/not in TINF chunks
+
+Unknown 1 (contained only in Track at Once images)
+ 4 Chunk ID "RELO"
+ 4 Chunk size (bytes)
+ 4 Zero
+
+Unknown 2 (contained only in Track at Once images)
+ 4 Chunk ID "TOCT"
+ 4 Chunk size (bytes)
+ 1 Disk type (00h=Mode1 or Audio, 20h=XA/Mode2) (and probably 10h=CD-I?)
+ 1 Zero (00h)
+
+Session Info (begin of a session) (contained only in multi-session images)
+ 4 Chunk ID "SINF"
+ 4 Chunk size (bytes)
+ 4 Number of tracks in session
+
+CD-Text (contained only in whatever images)
+ 4 Chunk ID None/"CDTX"
+ 4 Chunk size (bytes) (must be a multiple of 18 bytes)
+below repeated for each fragment,
+ 18 Raw 18-byte CD-text data fragments
+
+Media Type? (contained only in whatever images)
+ 4 Chunk ID "MTYP"
+ 4 Chunk size (bytes)
+ 4 Unknown? (00000001h for CDROM) (maybe other value for DVD)
+
+Notes
+Newer/older .NRG files may contain 32bit/64bit values (and use "OLD"/"NEW"
+chunk names) (as indicated by the "/" slashes).
+CAUTION: All 16bit/32bit/64bit values are in big endian byte-order.
+
+Missing
+Unknown if newer NRG versions do also support subchannel data.
+
+CDROM Disk Image/Containers CDZ
+-------------------------------
+
+.CDZ is a compressed disk image container format (developed by pSX Author, and
+used only by the pSX emulator). The disk is split into 64kbyte blocks, which
+allows fast random access (without needing to decompress all preceeding
+sectors).
+However, the compression ratio is surprisingly bad (despite of being
+specifically designed for cdrom compression, the format doesn't remove
+redundant sector headers, error correction information, and EDC checksums).
+
+.CDZ File Structure
+ FileID ("CDZ",00h for cdztool v0/v1, or "CDZ",01h for cdztool v2 and up)
+ One or two Chunk(s)
+
+.CDZ Chunk Format
+Chunk Header in v0 (unreleased prototype):
+ 4 32bit Decompressed Size (of all blocks) (must be other than "ZLIB")
+Chunk Header in v1 (first released version):
+ 4 ZLIB ID ("ZLIB")
+ 8 64bit Decompressed Size (of all blocks)
+Chunk Header in v2 and up (later versions):
+ 4 Chunk ID (eg. "CUE",00h)
+ 8 Chunk Size in bytes (starting at "ZLIB" up to including Footer, if any)
+ 4 ZLIB ID ("ZLIB")
+ 8 64bit Decompressed Size (of all blocks)
+Chunk Body (same in all versions):
+ 4 Number of Blocks (N)
+ 4 Block 1 Compressed Size (CS.1)
+ 4 Block 1 Decompressed Size (always 00010000h, except last block)
+ CS.1 Block 1 Compressed ZLIB Data (starting with 78h,9Ch)
+ ... ... ;\
+ 4 Block N Compressed Size (CS.N) ; further block(s)
+ 4 Block N Decompressed Size ; (if any)
+ CS.N Block N Compressed ZLIB Data ;/
+Chunk Footer in v0 (when above header didn't have the "ZLIB" ID):
+ 4*N Directory Entries for N blocks ;-this ONLY for BIN chunk
+Chunk Footer in v1 and up:
+ BPD*(N-1) Directory Entries for N-1 blocks ;\this ONLY for BIN chunk
+ 1 Bytes per Directory Entry (BPD) ;/(not for CUE/CCD/MDS)
+The "Compressed ZLIB Data" parts contain Deflate'd data (starting with 2-byte
+ZLIB header, and ending with 4-byte ZLIB/ADLER checksum), for details see:
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+
+.CDZ Chunks / Content
+The chunk(s) have following content:
+ noname+noname --> .CUE+.BIN (cdztool v1 and below)
+ "BIN",0 --> .ISO (cdztool v2? and up)
+ "CUE",0+"BIN",0 --> .CUE+.BIN (cdztool v2 and up)
+ "CCD",0+"BIN",0 --> .CCD+.IMG (cdztool v2 and up)
+ "CCD",0+"BIN",01h --> .CCD+.IMG+.SUB (930h sectors, plus 60h subchannels)
+ "MDS",0+"BIN",0 --> .MDS+.MDF (cdztool v5 only)
+Note: cdztool doesn't actually recognize files with .ISO extension (however,
+one can rename them to .BIN, and then compress them as CUE-less .BIN file).
+
+Cdztool.exe Versions
+ cdztool.exe v0, unrelased prototype
+ cdztool.exe v1, 22 May 2005, CRC32=620dbb08, 102400 bytes, pSX v1.0-5
+ cdztool.exe v2, 02 Jul 2006, CRC32=bcb29c1e, 110592 bytes, pSX v1.6
+ cdztool.exe v3, 22 Jul 2006, CRC32=4062ba82, 110592 bytes, pSX v1.7
+ cdztool.exe v4, 13 Aug 2006, CRC32=7388dd3d, 118784 bytes, pSX v1.8-11
+ cdztool.exe v5, 22 Jul 2007, CRC32=f25c1659, 155648 bytes, pSX v1.12-13
+Note: v0 wasn't ever released (it's only noteworthy because later versions do
+have backwards compatibility for decompressing old v0 files). v1 didn't work
+with all operating systems (on Win98 it just says "Error: Couldn't create
+<output>" no matter what one is doing, however, v1 does work on later windows
+versions like WinXP or so?).
+
+CDROM Disk Image/Containers ECM
+-------------------------------
+
+ECM (Error Code Modeler by Neill Corlett) is a utility that removes
+unneccessary ECC error correction and EDC error detection values from
+CDROM-images. This is making the images a bit smaller, but the real size
+reduction isn't gained until subsequently compressing the images via tools like
+ZIP. Accordingly, these files are extremly uncomfortable to use: One most first
+UNZIP them, and then UNECM them.
+
+.EXT.ECM - Double extension
+ECM can be applied to various CDROM-image formats (like .BIN, .CDI, .IMG, .ISO,
+.MDF, .NRG), as indicated by the double-extension. Most commonly it's applied
+to .BIN files (hence using extension .BIN.ECM).
+
+Example / File Structure
+ 45 43 4D 00 ;FileID "ECM",00h
+ 3C ;Type 0, Len=10h (aka 0Fh+1)
+ 00 FF FF FF FF FF FF FF FF FF FF 00 00 02 00 02 ;16 data bytes
+ 02 ;Type 2, Len=1 (aka 00h+1)
+ 00 00 08 00 00 00 00 00 00 00 00 ..... 00 00 00 ;804h data bytes
+ 3C ;Type 0, Len=10h (aka 0Fh+1)
+ 00 FF FF FF FF FF FF FF FF FF FF 00 00 02 01 02 ;16 data bytes
+ 02 ;Type 2, Len=1 (aka 00h+1)
+ 00 00 08 00 00 00 00 00 00 00 00 ..... 00 00 00 ;804h data bytes
+ ...
+ FC FF FF FF 3F ;End Code (Len=FFFFFFFFh+1)
+ NN NN NN NN ;EDC (on decompressed data)
+
+Type/Length Byte(s)
+Type/Length is encoded in 1..5 byte(s), with "More=1" indicating that further
+length byte(s) follow:
+ 1st Byte: Bit7=More, Bit6-2=LengthBit4-0, Bit1-0=Type(0..3)
+ 2nd Byte: Bit7=More, Bit6-0=LengthBit5-11
+ 3rd Byte: Bit7=More, Bit6-0=LengthBit12-18
+ 4th Byte: Bit7=More, Bit6-0=LengthBit19-25
+ 5th Byte: Bit7-6=Reserved/Zero, Bit5-0=LengthBit26-31
+Length=FFFFFFFFh=End Indicator
+The actual decompression LEN is: "LEN=Length+1"
+
+ECM Decompression
+Below is repeated LEN times (with LEN being the Length value plus 1):
+ Type 0: load 1 byte, save 1 byte
+ Type 1: load 803h bytes [0Ch..0Eh,10h..80Fh], save 930h bytes [0..92Fh]
+ Type 2: load 804h bytes [14h..817h], save 920h bytes [10h..92Fh]
+ Type 3: load 918h bytes [14h..91Bh], save 920h bytes [10h..92Fh]
+Type 1-3 are reconstructing the missing bytes before saving. Type 2-3 are
+saving only 920h bytes, so (if the original image contained full 930h byte
+sectors) the missing 10h bytes must be inserted via Type 0. Type 0 can be also
+used for copying whole sectors as-is (eg. Audio sectors, or Data sectors with
+invalid Sync/Header/ECC/EDC values). And, Type 0 can be used to store
+non-sector data (such like the chunks at the end of .NRG or .CDI files).
+
+Central Mistakes
+There's a lot of wrong with the ECM format. The two central problems are that
+it doesn't support data-compression (and needs external compression tools like
+zip/rar), and, that it doesn't contain a sector look-up table (meaning that
+random access isn't possible unless when scanning the whole file until reaching
+the desired sector).
+
+Worst-case Scenario
+As if ECM as such wouldn't be uncomfortable enough, you may expect typical ECM
+users to get more things messed up. For example:
+ A RAR file containing a 7Z file containing a ECM file containing a BIN file.
+ The BIN containing only Track 1, other tracks stored in APE files.
+ And, of course, the whole mess without including the required CUE file.
+
+CDROM Subchannel Images
+-----------------------
+
+SBI (redump.org)
+SBI Files start with a 4-byte FileID:
+ 4 bytes FileID ("SBI",00h)
+The followed by entries as so:
+ 3 bytes real absolute MM:SS:FF address where the sub q data was bad
+ 1 byte Format: the format can be 1, 2 or 3:
+ Format 1: complete 10 bytes sub q data (Q0..Q9)
+ Format 2: 3 bytes wrong relative MM:SS:FF address (Q3..Q5)
+ Format 3: 3 bytes wrong absolute MM:SS:FF address (Q7..Q9)
+Note: The PSX libcrypt protection relies on bad checksums (Q10..Q11), which
+will cause the PSX cdrom controller to ignore Q0..Q9 (and to keep returning
+position data from most recent sector with intact checksum).
+Ironically, the SBI format cannot store the required Q10..Q11 checksum. The
+trick for using SBI files with libcrypted PSX discs is to ignore the useless
+Q0..Q9 data, and to assume that all sectors in the SBI file have wrong Q10..Q11
+checksums.
+
+M3S (Subchannel Q Data for Minute 3) (ePSXe)
+M3S files are containing Subchannel Q data for all sectors on Minute=03 (the
+region where PSX libcrypt data is located) (there is no support for storing the
+(unused) libcrypt backup copy on Minute=09). The .M3S filesize is 72000 bytes
+(60 seconds * 75 sectors * 16 bytes). The 16 bytes per sector are:
+ Q0..Q9 Subchannel Q data (normally position data)
+ Q10..Q11 Subchannel Q checksum
+ Q12..Q15 Dummy/garbage/padding (usually 00000000h or FFFFFFFFh)
+Unfortunately, there are at least 3 variants of the format:
+ 1. With CRC (Q0..Q11 intact) (and Q12..Q15 randomly 00000000h or FFFFFFFFh)
+ 2. Without CRC (only Q0..Q9 intact, but Q10..Q15 zerofilled)
+ 3. Without anything (only Q0 intact, but Q1..Q15 zerofilled)
+The third variant is definetly corrupt (and one should ignore such zerofilled
+entries). The second variant is corrupt, too (but one might attempt to repair
+them by guessing the missing checksum: if it contains normal position values
+assume correct crc, if it contains uncommon values assume a libcrypted sector
+with bad crc).
+The M3S format is intended for libcrypted PSX games, but, people seem to have
+also recorded (corrupted) M3S files for unprotected PSX games (in so far, more
+than often, the M3S files might cause problems, instead of solving them).
+Note: The odd 16-byte format with 4-byte padding does somehow resemble the "P
+and Q Sub-Channel" format 'defined' in MMC-drafts; if the .M3S format was based
+on the MMC stuff: then the 16th byte might contain a Subchannel P "pause" flag
+in bit7.
+
+CDROM Images with Subchannel Data
+Most CDROM-Image formats can (optionally) contain subchannel recordings. The
+downsides are: Storing all 8 subchannels for a full CDROM takes up about
+20MBytes. And, some entries may contain 'wrong' data (read errors caused by
+scratches cannot be automatically repaired since subchannels do not contain
+error correction info).
+If present, the subchannel data is usually appended at the end of each sector
+in the main binary file (one exception is CloneCD, which stores it in a
+separate .SUB file instead of in the .IMG file).
+ CCD/IMG/SUB (CloneCD) P-W 60h-bytes Non-interleaved (in separate .SUB file)
+ CDI (DiscJuggler) P-Q 10h-bytes Non-interleaved (in .CDI file)
+ "" P-W 60h-bytes Interleaved (in .CDI file)
+ CUE/BIN/CDT (Cdrwin) N/A
+ ISO (single-track) N/A
+ MDS/MDF (Alcohol 120%) P-W 60h-bytes Interleaved (in .MDF file)
+ NRG (Nero) P-W 60h-bytes Interleaved (in .NRG file)
+Interleaved Subchannel format (eg. Alcohol .MDF files):
+ 00h-07h 80 C0 80 80 80 80 80 C0 ;P=FFh, Q=41h=ADR/Control, R..W=00h
+ 08h-0Fh 80 80 80 80 80 80 80 C0 ;P=FFh, Q=01h=Track, R..W=00h
+ 10h-17h 80 80 80 80 80 80 80 C0 ;P=FFh, Q=01h=Index, R..W=00h
+ 18h-1Fh 80 80 80 80 80 80 80 80 ;P=FFh, Q=00h=RelMinute, R..W=00h
+ 20h-27h 80 80 80 80 80 80 80 80 ;P=FFh, Q=00h=RelSecond, R..W=00h
+ 28h-2Fh 80 80 80 80 80 80 80 80 ;P=FFh, Q=00h=RelSector, R..W=00h
+ 30h-37h 80 80 80 80 80 80 80 80 ;P=FFh, Q=00h=Reserved, R..W=00h
+ 38h-3Fh 80 80 80 80 80 80 80 80 ;P=FFh, Q=00h=AbsMinute, R..W=00h
+ 40h-47h 80 80 80 80 80 80 C0 80 ;P=FFh, Q=02h=AbsSecond, R..W=00h
+ 48h-4Fh 80 80 80 80 80 80 80 80 ;P=FFh, Q=00h=AbsSector, R..W=00h
+ 50h-57h 80 80 C0 80 C0 80 80 80 ;P=FFh, Q=28h=ChecksumMsb, R..W=00h
+ 58h-5Fh 80 80 C0 C0 80 80 C0 80 ;P=FFh, Q=32h=ChecksumLsb, R..W=00h
+Non-Interleaved Subchannel format (eg. CloneCD .SUB files):
+ 00h-0Bh FF FF FF FF FF FF FF FF FF FF FF FF ;Subchannel P (Pause)
+ 0Ch-17h 41 01 01 00 00 00 00 00 02 00 28 32 ;Subchannel Q (Position)
+ 18h-23h 00 00 00 00 00 00 00 00 00 00 00 00 ;Subchannel R
+ 24h-2Fh 00 00 00 00 00 00 00 00 00 00 00 00 ;Subchannel S
+ 30h-3Bh 00 00 00 00 00 00 00 00 00 00 00 00 ;Subchannel T
+ 3Ch-47h 00 00 00 00 00 00 00 00 00 00 00 00 ;Subchannel U
+ 48h-53h 00 00 00 00 00 00 00 00 00 00 00 00 ;Subchannel V
+ 54h-5Fh 00 00 00 00 00 00 00 00 00 00 00 00 ;Subchannel W
+Non-Interleaved P-Q 10h-byte Subchannel format:
+ This is probably based on MMC protocol, which would be as crude as this:
+ The 96 pause bits are summarized in 1 bit. Pause/Checksum are optional.
+ 00h-09h 41 01 01 00 00 00 00 00 02 00 ;Subchannel Q (Position)
+ 0Ah-0Bh 28 32 ;<-- OPTIONAL, can be zero! ;Subchannel Q (Checksum)
+ 0Ch-0Eh 00 00 00 ;Unused padding (zero)
+ 0F 80 ;<-- OPTIONAL, can be zero! ;Subchannel P (Bit7=Pause)
+
+CDROM Disk Images Other Formats
+-------------------------------
+
+.ISO - A raw ISO9660 image (can contain a single data track only)
+Contains raw sectors without any sub-channel information (and thus it's
+restricted to the ISO filesystem region only, and cannot contain extras like
+additional audio tracks or additional sessions). The image should start at
+00:02:00 (although I wouldn't be surprised if some <might> start at 00:00:00 or
+so). Obviously, all sectors must have the same size, either 800h or 930h bytes
+(if the image contains only Mode1 or Mode2/Form1 sectors then 800h bytes would
+usually enough; if it contains one or more Mode2/Form2 sectors then all sectors
+should be 930h bytes).
+Handling .ISO files does thus require to detect the image's sector size, and to
+search the sector that contains the first ISO Volume Descriptor. In case of
+800h byte sectors it may be additionally required to detect if it is a Mode1 or
+Mode2/Form1 image; for PSX images (and any CD-XA images) it'd be Mode2.
+
+.CHD
+Something used by MAME/MESS. Originally intended for compressed ROM-images, but
+does also support compressed CDROM-images. Fileformat and compression ratio are
+unknown. Also unknown if it allows random-access.
+Some info can be found in MAME source code (looking at the source code for the
+CHDMAN tool might be a good starting point... although the actual file
+structure might be hidden in other source files).
+
+.C2D
+Something. Can contain compressed or uncompressed CDROM-images. Fileformat and
+compression ratio are unknown. Also unknown if it allows random-access.
+Some info on (uncompressed) .C2D files can be found in libmirage source code.
+
+.ISZ
+This is reportedly a "zipped" .ISO file, using some unknown compression format
+(unrelated to pkzip .zip file format).
+
+.MDX
+Reportedly a compressed MDS/MDF file, supported by Daemon Tools. Fileformat and
+compression ratio are unknown. Also unknown if it allows random-access.
+
+.CU2/.BIN
+Custom format used by PSIO (an SD-card based CDROM-drive emulator connected to
+PSX expansion port). The .CU2 file is somewhat intended to be smaller and
+easier to parse than normal .CUE files, the drawback is that it's kinda
+non-standard, and doesn't support INDEX and ADSR information. A sample .CUE
+file looks as so:
+ ntracks 3
+ size 39:33:17
+ data1 00:02:00
+ track02 31:36:46
+ track03 36:03:17
+ ;(insert 2 blanks lines here, and insert 1 leading space in next line)
+ trk end 39:37:17
+All track numbers and MM:SS:FF values are decimal. The ASCII strings should be
+as shown above, but they are simple ignored by the PSIO firmware (eg. using
+"popcorn666" instead of "size" or "track02" should also work). The first track
+should be marked "data1", but PSIO ignores that string, too (it does always
+treat track 1 as data, and track 2-99 as audio; thus not supporting PSX games
+with multiple data tracks). The "trk end" value should be equal to the "size"
+value plus 4 seconds (purpose is unknown, PSIO does just ignore the "trk end"
+value).
+CU2 creation seems to require CDROM images in "CUE/BIN redump.org format" (with
+separate BIN files for each track), the CUE is then converted to a CU3 file
+(which is used only temporarily), until the whole stuff is finally converted to
+a CU2 file (and with all tracks in a single BIN file). Tools like RD2PSIO (aka
+redump2psio) or PSIO's own SYSCON.ZIP might help on doing some of those steps
+automatically.
+Alongsides, PSIO uses a "multidisc.lst" file... for games that require more
+than one CDROM disc?
+
+CD Image File Format (Xe - Multi System Emulator)
+This is a rather crude file format, used only by the Xe Emulator. The files are
+meant to be generated by a utility called CDR (CD Image Ripper), which, in
+practice merely displays an "Unable to read TOC." error message.
+The overall file structure is, according to "Xe User's Manual":
+ header: 200h bytes header (see below)
+ data: 990h bytes per sector (2352 Main, 96 Sub), 00:00:00->Lead Out
+The header "definition" from the "Xe User's Manual" is as unclear as this:
+ 000h 00
+ 001h 00
+ 002h First Track
+ 003h Last Track
+ 004h Track 1 (ADR << 4) | CTRL ;\
+ 005h Track 1 Start Minutes ; Track 1
+ 006h Track 1 Start Seconds ;
+ 007h Track 1 Start Frames ;/
+ ... ... ;-Probably Further Tracks (?)
+ n+0 Last Track Start Minutes ;\
+ n+1 Last Track Start Seconds ; Last Track
+ n+2 Last Track Start Frames ;
+ n+3 Last Track (ADR << 4) | CTRL ;/
+ n+4 Lead-Out Track Start Minutes ;\
+ n+5 Lead-Out Track Start Seconds ; Lead-Out
+ n+6 Lead-Out Track Start Frames ;
+ n+7 Lead-Out Track (ADR << 4) | CTRL ;/
+ ... 00
+ 1FFh 00
+Unknown if MM:SS:FF values and/or First+Last Track numbers are BCD or non-BCD.
+Unknown if Last track is separately defined even if there is only ONE track.
+Unknown if Track 2 and up include ADR/Control (and if yes: where?).
+Unknown if ADR/Control is really meant to be <before> MM:SS:FF on Track 1.
+Unknown if ADR/Control is really meant to be <after> MM:SS:FF on Last+Lead-Out.
+Unknown if this format does have a file extension (if yes: which?).
+Unknown if subchannel data is meant to be interleaved or not.
+The format supports only around max 62 tracks (in case each track is 4 bytes).
+There is no support for "special" features like multi-sessions, cd-text.
+
+CDROM Internal Info on PSX CDROM Controller
+-------------------------------------------
+
+PSX software can access the CDROM via Port 1F801800h..1F801803h (as described
+in the previous chapters). The following chapters describe the inner workings
+of the PSX CDROM controller - this information is here for curiosity only -
+normally PSX software cannot gain control of those lower-level stuff (although
+some low level registers can be manipulated via Test commands, but that will
+usually conflict with normal operation).
+
+Motorola MC68HC05 (8bit single-chip CPU)
+The Playstation CDROM drive is controlled by a MC68HC05 8bit CPU with on-chip
+I/O ports and on-chip BIOS ROM. There is no way to reprogram that BIOS, nor to
+tweak it to execute custom code in RAM.
+--> CDROM Internal HC05 Instruction Set
+--> CDROM Internal HC05 On-Chip I/O Ports
+--> CDROM Internal HC05 I/O Port Usage in PSX
+--> CDROM Internal HC05 Motorola Selftest Mode
+The PSX can read HC05 I/O Ports and RAM via Test Commands:
+--> CDROM - Test Commands - Read HC05 SUB-CPU RAM and I/O Ports
+
+Decoder/FIFO (CXD1199BQ or CXD1815Q)
+This chip handles error correction and ADPCM decoding, and acts as some sort of
+FIFO interface between main/sub CPUs and incoming cdrom sector data. On the
+MIPS Main CPU it is controlled via Port 1F801800h..1F801803h.
+--> CDROM Controller I/O Ports
+On the HC05 Sub CPU it is controlled via Port A (data in/out), Port E
+(address/index), and Port D (read/write/select signals); the HC05 doesn't have
+external address/data bus, so one must manually access the CXD1815Q via those
+ports.
+--> CDROM Internal CXD1815Q Sub-CPU Configuration Registers
+--> CDROM Internal CXD1815Q Sub-CPU Sector Status Registers
+--> CDROM Internal CXD1815Q Sub-CPU Address Registers
+--> CDROM Internal CXD1815Q Sub-CPU Misc Registers
+The PSX can read/write the Decoder I/O Ports and SRAM via Test commands:
+--> CDROM - Test Commands - Read/Write Decoder RAM and I/O Ports
+The sector buffer used in the PSX is 32Kx8 SRAM. Old PU-7 boards are using
+CXD1199BQ chips, later boards are using CXD1815Q, and even later boards have
+the stuff intergrated in the SPU. Note: The CXD1199BQ/CXD1815Q are about 99%
+same as described in CXD1199AQ datasheet.
+
+Signal Processor and Servo Amplifier
+Older PSX mainboards are using two separate chips:
+--> CDROM Internal Commands CX(0x..3x) - CXA1782BR Servo Amplifier
+--> CDROM Internal Commands CX(4x..Ex) - CXD2510Q Signal Processor
+Later PSX mainboards have the above intergrated in a single chip, with some
+extended features:
+--> CDROM Internal Commands CX(0x..Ex) - CXD2545Q Servo/Signal Combo
+Later version is CXD1817R (Servo/Signal/Decoder Combo).
+Even later PSX mainboards have it integrated in the Sound Chip: CXD2938Q
+(SPU+CDROM) with some changed bits and New SCEx transfer:
+--> CDROM Internal Commands CX(0x..Ex) - CXD2938Q Servo/Signal/SPU Combo
+Finally, PM-41(2) boards are using a CXD2941R chip (SPU+CDROM+SPU_RAM), unknown
+if/how far the CDROM part of that chip differs from CXD2938Q.
+Some general notes:
+--> CDROM Internal Commands CX(xx) - Notes
+--> CDROM Internal Commands CX(xx) - Summary of Used CX(xx) Commands
+The PSX can manipulate the CX(..) registers via some test commands:
+--> CDROM - Test Commands - Test Drive Mechanics
+Note: Datasheets for CXD2510Q/CXA1782BR/CXD2545Q do exist.
+
+CDROM Pinouts
+--> Pinouts - DRV Pinouts
+--> Pinouts - HC05 Pinouts
+
+CDROM Internal HC05 Instruction Set
+-----------------------------------
+
+ALU, Load/Store, Jump/Call
+ Opcode Clk HINZC Name Syntax
+ x6 ... 2-5 --NZ- LDA MOV A,<op> ;A=op
+ xE ... 2-5 --NZ- LDX MOV X,<op> ;X=op
+ x7 ... 4-6 --NZ- STA MOV <op>,A ;op=A
+ xF ... 4-6 --NZ- STX MOV <op>,X ;op=X
+ xC ... 2-4 ----- JMP JMP <op> ;PC=op
+ xD ... 5-7 ----- JSR CALL <op> ;[SP]=PC, PC=op
+ xB ... 2-5 H-NZC ADD ADD A,<op> ;A=A+op
+ x9 ... 2-5 H-NZC ADC ADC A,<op> ;A=A+op+C
+ x0 ... 2-5 --NZC SUB SUB A,<op> ;A=A-op
+ x2 ... 2-5 --NZC SBC SBC A,<op> ;A=A-op-C
+ x4 ... 2-5 --NZ- AND AND A,<op> ;A=A AND op
+ xA ... 2-5 --NZ- ORA OR A,<op> ;A=A OR op
+ x8 ... 2-5 --NZ- EOR XOR A,<op> ;A=A XOR op
+ x1 ... 2-5 --NZC CMP CMP A,<op> ;A-op
+ x3 ... 2-5 --NZC CPX CMP X,<op> ;X-op
+ x5 ... 2-5 --NZ- BIT TEST A,<op> ;A AND op
+ A7,AF,AC = Reserved (no STA/STX/JMP with immediate operand)
+Operands can be...
+ Opcode Clk ALU/LDA/LDX Clk STA/STX Clk JMP/CALL
+ Ax nn 2 cmd r,nn - N/A -/6 call relative (BSR)
+ Bx nn 3 cmd r,[nn] 4 mov [nn],r 2/5 cmd nn
+ Cx nn mm 4 cmd r,[nnmm] 5 mov [nnmm],r 3/6 cmd nnmm
+ Dx nn mm 5 cmd r,[X+nnmm] 6 mov [X+nnmm],r 4/7 cmd X+nnmm
+ Ex nn 4 cmd r,[X+nn] 5 mov [X+nn],r 3/6 cmd X+nn
+ Fx 3 cmd r,[X] 4 mov [X],r 2/5 cmd X
+
+Read-Modify-Write
+ Opcode Clk HINZC Name Syntax
+ xC ... 3-6 --NZ- INC INC op ;increment ;op=op+1
+ xA ... 3-6 --NZ- DEC DEC op ;decrement ;op=op-1
+ xF ... 3-6 --01- CLR ?? op,00h ;clear ;op=op AND 00h
+ x3 ... 3-6 --NZ1 COM NOT op ;complement ;op=op XOR FFh
+ x0 ... 3-6 --NZC NEG NEG op ;negate ;op=00h-op
+ x9 ... 3-6 --NZC ROL RCL op ;rotate left through carry
+ x6 ... 3-6 --NZC ROR RCR op ;rotate right through carry
+ x8 ... 3-6 --NZC LSL SHL op ;shift left logical
+ x4 ... 3-6 --0ZC LSR SHR op ;shift right logical
+ x7 ... 3-6 --NZC ASR SAR op ;shift right arithmetic
+ xD ... 3-5 --NZ- TST TEST op,FFh ;test for negative or zero (AND FFh?)
+ x1,x2,x5,xB,xE = Reserved (except for: 42 = MUL)
+Operands can be...
+ Opcode Clk RMW Clk CLR Clk TST
+ 3x nn 5 cmd [nn] 5 MOV [nn],00h 4 TEST [nn],0FFh
+ 4x 3 cmd A 3 MOV A,00h,slow 3 TEST A,0FFh,slow
+ 5x 3 cmd X 3 MOV X,00h,slow 3 TEST X,0FFh
+ 6x nn 6 cmd [X+nn] 6 MOV [X+nn],00h 5 TEST [X+nn],0FFh
+ 7x 5 cmd [X] 5 MOV [X],00h 4 TEST [X],0FFh
+CLR includes a dummy-read-cycle, whilst TST does omit the dummy-write cycle.
+The ",slow" RMW opcodes are smaller, but slower than equivalent ALU opcodes.
+
+Bit Manipulation and Bit Test with Relative Jump (to $+3+/-dd)
+ Opcode Clk HINZC Name Syntax
+ 00h+i*2 nn dd 5 ----C BRSET JNZ [nn].i,dest ;C=[nn].i, branch if set
+ 01h+i*2 nn dd 5 ----C BRCLR JZ [nn].i,dest ;C=[nn].i, branch if clear
+ 10h+i*2 nn 5 ----- BSET SET [nn].i ;set [nn].i
+ 11h+i*2 nn 5 ----- BCLR RES [nn].i ;clear [nn].i
+
+Branch (Relative jump to $+2+/-nn)
+ Opcode Clk HINZC Name Syntax
+ 20 nn 3 ----- BRA JR nn ;branch always
+ 21 nn 3 ----- BRN NUL nn ;branch never
+ 22 nn 3 ----- BHI JA nn ;if C=0 and Z=0, higher ?
+ 23 nn 3 ----- BLS JBE nn ;if C=1 or Z=1, lower or same ?
+ 24 nn 3 ----- BCC/BHS JNC/JAE nn ;if C=0, carry clear, higher.same
+ 25 nn 3 ----- BCS/BLO JC/JB nn ;if C=1, carry set, lower
+ 26 nn 3 ----- BNE JNZ/JNE nn ;if Z=0, not equal / not zero
+ 27 nn 3 ----- BEQ JZ/JE nn ;if Z=1, equal / zero
+ 28 nn 3 ----- BHCC JNH nn ;if H=0, half-carry clear
+ 29 nn 3 ----- BHCS JH nn ;if H=1, half-carry set
+ 2A nn 3 ----- BPL JNS nn ;if S=0, plus / not signed
+ 2B nn 3 ----- BMI JS nn ;if S=1, minus / signed
+ 2C nn 3 ----- BMC JEI nn ;if I=0, interrupt mask clear
+ 2D nn 3 ----- BMS JDI nn ;if I=1, interrupt mask set
+ 2E nn 3 ----- BIL JIL nn ;if XX=LO, interrupt line low
+ 2F nn 3 ----- BIH JIH nn ;if XX=HI, interrupt line high
+ AD nn 6 ----- BSR CALL relative nn ;branch to subroutine always
+
+Control/Misc
+ Opcode Clk HINZC Name Syntax
+ 9D 2 ----- NOP NOP ;no operation
+ 97 2 ----- TAX MOV X,A ;transfer A to X
+ 9F 2 ----- TXA MOV A,X ;transfer X to A
+ 9C 2 ----- RSP MOV SP,00FFh ;reset stack pointer (SP=00FFh)
+ 42 11 0---0 MUL MUL X,A ;X:A=X*A (unsigned multiply)
+ 81 6 ----- RTS RET ;return from subroutine
+ 80 9 xxxxx RTI RETI ;return from interrupt
+ 99 2 ----1 SEC STC ;set carry flag
+ 98 2 ----0 CLC CLC ;clear carry flag
+ 9B 2 -1--- SEI DI ;set interrupt mask (disable ints)
+ 9A 2 -0--- CLI EI ;clear interrupt mask (enable ints)
+ 8E ..2 -0--- STOP STOP ;?
+ 8F ..2 -0--- WAIT WAIT ;?
+ 83 10 -1--- SWI SWI ;software interrupt ...? PC=[FFFCh]
+ <IRQ> ? ????? Interrupt ;? PC=[FFFxh]
+ <RESET> ? ????? Reset ;? PC=[FFFEh]
+ 82,84..8D,90..96,9E = Reserved
+MUL isn't supported in original "M146805 CMOS" family (MUL is used/supported in
+PSX cdrom controller).
+
+Registers
+ A 8bit accumulator
+ X 8bit index register
+ SP 6bit stack pointer (range 00C0h..00FFh)
+ PC 16bit program pointer (range 0000h..FFFFh)
+ CCR 5bit condition code register (flags) (111HINZC)
+
+Pushed on IRQ are:
+ SP.highest PC.lo
+ PC.hi
+ X
+ A
+ SP.lowest Flags (CCR, 5bit condition code register) (111HINZC)
+
+Addressing Modes
+ nn immediate ;00h..FFh
+ [nn] direct address ;[0000h..00FFh]
+ [nnmm] extended address ;[0000h..FFFFh]
+ [X] indexed, no offset ;[0000h..00FFh]
+ [X+nn] indexed, 8bit offset ;[0000h..01FEh]
+ [X+nnmm] indexed, 16bit offset ;[0000h..FFFFh]
+ [nn].i bit ;[0000h..00FFh].bit0..7
+ dd relative ;$+2..3+(-80h..+7Fh)
+Notes:
+ operand "X+nn" performs an unsigned addition, and can address 0000h..01FEh.
+ 16bit operands (nnmm) are encoded in BIG-ENDIAN format (same for pushed PC).
+
+Exception Vectors
+Exception vectors are 16bit BIG-ENDIAN values at FFF0h-FFFFh (or at FFE0h-FFEFh
+when running in Motorola Bootstrap mode).
+ Vector Prio Usage
+ FFF0h 7=lo TBI Vector (Timebase)
+ FFF2h 6 SSPI Vector (SPI bus) (SPI1 and SPI2)
+ FFF4h 5 Timer 2 Interrupt Vector (Timer 2 Input/Compare)
+ FFF6h 4 Timer 1 Interrupt Vector (Timer 1 Input/Compare/Overflow)
+ FFF8h 3 KWI Vector (Key Wakeup) (KWI0..7 pins)
+ FFFAh 2 External Interrupt Vector (/IRQ1 and /IRQ2 pins)
+ FFFCh none Software Interrupt Vector (SWI opcode) ;\regardless of
+ FFFEh 1=hi Reset Vector (/RESET signal and COP) ;/CPU's "I"
+
+Directives/Pseudos (used by a22i assembler; in no$psx utility menu)
+ .hc05 select HC05 instruction set (default would be .mips)
+ .nocash select nocash syntax (default would be .native opcode names)
+ db ... define 8bit byte(s), or quoted ascii strings
+ dw ... define 16bit word(s) in BIG ENDIAN (for HC05 exception vectors)
+ org nnnn change origin for following opcodes
+ end end of file
+ mov c,[nn].i alias for "jnz [nn].i,$+3" (dummy jump & set carry=[nn].i)
+
+CDROM Internal HC05 On-Chip I/O Ports
+-------------------------------------
+
+HC05 Port 3Eh - MISC - Miscellaneous Register (R/W)
+ 0 OPTM Option Map Select (bank-switching for Port 00h..0Fh)
+ 1 FOSCE Fast (Main) Oscillator Enable (0=Disable OSC, 1=Normal)
+ 2-3 SYS System Clock Select (0=OSC/2, 1=OSC/4, 2=OSC/64, 3=XOSC/2)
+ 4-5 - Not used (0)
+ 6 STUP XOSC Time Up Flag (R)
+ 7 FTUP OSC Time Up Flag (R) (0=Busy, 1=Ready/Good/Stable)
+Note: For PSX, OSC is 4.0000MHz (PU-7/PU-8), 4.2336MHz (PU-18 and up). SysClk
+is usually set to OSC/2, ie. around 2MHz.
+
+HC05 Port OPTM=0:00h - PORTA - Port A Data Register (R/W)
+HC05 Port OPTM=0:01h - PORTB - Port B Data Register (R)
+HC05 Port OPTM=0:02h - PORTC - Port C Data Register (R/W)
+HC05 Port OPTM=0:03h - PORTD - Port D Data Register (R/W)
+HC05 Port OPTM=0:04h - PORTE - Port E Data Register (R/W)
+HC05 Port OPTM=0:05h - PORTF - Port F Data Register (R) (undoc: R/W)
+These are general purpose I/O ports (controlling external pins). Some ports are
+Input-only, and some can be optionally used for special things (like IRQs,
+SPI-bus, or as Timer input/output).
+ PA.0-7 PAn Port A Bit0..7 Input/Output (0=Low, 1=High) (R/W)
+ PB.0-7 PBn Port B Bit0..7 Input /KWI0..7 (0=Low, 1=High) (R)
+ PC.0 PC0 Port C Bit0 Input/Output /SDI1 (SPI)(0=Low, 1=High) (R/W)
+ PC.1 PC1 Port C Bit1 Input/Output /SDO1 (SPI)(0=Low, 1=High) (R/W)
+ PC.2 PC2 Port C Bit2 Input/Output /SCK1 (SPI)(0=Low, 1=High) (R/W)
+ PC.3 PC3 Port C Bit3 Input/Output /TCAP (T1) (0=Low, 1=High) (R/W)
+ PC.4 PC4 Port C Bit4 Input/Output /EVI (T2) (0=Low, 1=High) (R/W)
+ PC.5 PC5 Port C Bit5 Input/Output /EVO (T2) (0=Low, 1=High) (R/W)
+ PC.6 PC6 Port C Bit6 Input/Output /IRQ2 (0=Low, 1=High) (R/W)
+ PC.7 PC7 Port C Bit7 Input/Output /IRQ1 (0=Low, 1=High) (R/W)
+ PD.0-7 PDn Port D Bit0..7 Input/Output (0=Low, 1=High) (R/W)
+ PE.0-7 PEn Port E Bit0..7 Input/Output (0=Low, 1=High) (R/W)
+ PF.0-7 PFn Port F Bit0..7 Input/Undoc A/D-input (0=Low, 1=High) (R)(R/W)
+
+HC05 Port OPTM=1:00h - DDRA - Port A Data Direction Register (R/W)
+HC05 Port OPTM=1:02h - DDRC - Port C Data Direction Register (R/W)
+HC05 Port OPTM=1:03h - DDRD - Port D Data Direction Register (R/W)
+HC05 Port OPTM=1:04h - DDRE - Port E Data Direction Register (R/W)
+HC05 Port OPTM=1:05h - DDRF - Port F Data Direction Register (undoc)
+ DDRX.0-7 DDRXn Port X Data Direction Bit0..7 (0=Input, 1=Output) (R/W)
+Officially, there are no DDRB and DDRF registers (Port B and F are always
+Inputs). Although, actually, Motorola's Bootstrap RAM <does> manipulate DDRF.
+
+HC05 Port OPTM=1:08h - RCR1 - Resistor Control Register 1 (R/W)
+HC05 Port OPTM=1:09h - RCR2 - Resistor Control Register 2 (R/W)
+ RCR1.0 RAL Port A.Bit0-3 Pullup Resistors (0=Off, 1=On)
+ RCR1.1 RAH Port A.Bit4-7 Pullup Resistors (0=Off, 1=On)
+ RCR1.2 RBL Port B.Bit0-3 Pullup Resistors (0=Off, 1=On)
+ RCR1.3 RBH Port B.Bit4-7 Pullup Resistors (0=Off, 1=On)
+ RCR1.4 RGL Port G.Bit0-3 Pullup Resistors (0=Off, 1=On) ;\
+ RCR1.5 RGH Port G.Bit4-7 Pullup Resistors (0=Off, 1=On) ; on chips
+ RCR1.6 RHL Port H.Bit0-3 Pullup Resistors (0=Off, 1=On) ; with Port G,H
+ RCR1.7 RHH Port H.Bit4-7 Pullup Resistors (0=Off, 1=On) ;/
+ RCR2.0-7 RCn Port C.Bit0-7 Pullup Resistors (0=Off, 1=On)
+
+HC05 Port OPTM=1:0Ah - WOM1 - Open Drain Output Control Register 1 (R/W)
+HC05 Port OPTM=1:0Bh - WOM2 - Open Drain Output Control Register 2 (R/W)
+ WOM1.0 AWOML Port A.Bit0-3 Open Drain Mode when DDR=1 (0=No, 1=Open Drain)
+ WOM1.1 AWOMH Port A.Bit4-5 Open Drain Mode when DDR=1 (0=No, 1=Open Drain)
+ WOM1.2 GWOML Port G.Bit0-3 Open Drain Mode when DDR=1 (0=No, 1=Open Drain)
+ WOM1.3 GWOMH Port G.Bit4-5 Open Drain Mode when DDR=1 (0=No, 1=Open Drain)
+ WOM1.4 HWOML Port H.Bit0-3 Open Drain Mode when DDR=1 (0=No, 1=Open Drain)
+ WOM1.5 HWOMH Port H.Bit4-5 Open Drain Mode when DDR=1 (0=No, 1=Open Drain)
+ WOM1.6-7 - Not used (0)
+ WOM2.0-5 CWOMn Port C.Bit0..5 Open Drain Mode when DDR=1 (0=No, 1=Open Drain)
+ WOM2.6-7 - Not used (always both bits set)
+
+==== Interrupts =====
+
+HC05 Port OPTM=0:08h - INTCR - Interrupt Control Register (R/W)
+ 0-1 - Not used (0)
+ 2 IRQ2S IRQ2 Select Edge-Sensitive Only (0=LowLevelAndNegEdge, 1=NegEdge)
+ 3 IRQ1S IRQ1 Select Edge-Sensitive Only (0=LowLevelAndNegEdge, 1=NegEdge)
+ 4 KWIE Key Wakeup Interrupt Enable (0=Disable, 1=Enable)
+ 5 - Not used (0)
+ 6 IRQ2E IRQ2 Interrupt Enable (0=Disable, 1=Enable)
+ 7 IRQ1E IRQ1 Interrupt Enable (0=Disable, 1=Enable)
+
+HC05 Port OPTM=0:09h - INTSR - Interrupt Status Register (R and W)
+ 0 RKWIF Reset Key Wakeup Interrupt Flag (0=No Change, 1=Reset) (W)
+ 1 - Not used (0)
+ 2 RIRQ2 Reset IRQ2 Interrupt Flag (0=No Change, 1=Reset) (W)
+ 3 RIRQ1 Reset IRQ1 Interrupt Flag (0=No Change, 1=Reset) (W)
+ 4 KWIF Key Wakeup Interrupt Flag (PB/KWI) (0=No, 1=IRQ) (R)
+ 5 - Not used (0)
+ 6 IRQ2F IRQ2 Interrupt Flag (PC6) (0=No, 1=IRQ) (R)
+ 7 IRQ1F IRQ1 Interrupt Flag (PC7) (0=No, 1=IRQ) (R)
+
+HC05 Port OPTM=1:0Eh - KWIE - Key Wakeup Interrupt Enable Register (R/W)
+ 0-7 KWIEn Port B.Bit0..7 Key Wakeup Interrupt Enable (0=Disable, 1=Enable)
+
+==== SPI Bus ====
+
+HC05 Port OPTM=0:0Ah - SPCR1 - Serial Peripheral Control Register 1 (R/W)
+ 0 SPRn SPI Clock Rate (0=ProcessorClock/2, 1=ProcessorClock/16)
+ 1-3 - Not used (0)
+ 4 MSTRn SPI Master Mode Select (0=Slave/SCK.In, 1=Master/SCK.Out)
+ 5 DORDn SPI Data Transmission Order (0=MSB First, 1=LSB First)
+ 6 SPEn SPI Enable (SPI1:PortC, SPI2:PortG) (0=Disable, 1=Enable)
+ 7 SPIEn SPI Interrupt Enable (... ack HOW?) (0=Disable, 1=Enable)
+
+HC05 Port OPTM=0:0Bh - SPSR1 - Serial Peripheral Status Register 1 (R)
+ 0-5 - Not used (0)
+ 6 DCOLn SPI Data Collision Occurred (0=No, 1=Collision)
+ 7 SPIFn SPI Transfer Complete Flag (0=Busy, 1=Complete) (R)
+Note: SPSR1.7 appears to be reset after reading SPSR1 (probably same for
+SPSR1.6, and maybe also same for whatever SPI IRQ signal).
+
+HC05 Port OPTM=0:0Ch - SPDR1 - Serial Peripheral Data Register 1 (R/W)
+ 0-7 BITn Data to be sent / being received
+
+==== Time Base / Config ====
+
+HC05 Port 10h - TBCR1 - Time Base Control Register 1 (R/W)
+ 0-1 T2R Timer2 Prescaler (0=SysClk, 1=SysClk/4, 2=SysClk/32, 3=SysClk/256)
+ 2-3 T3R PWM Prescaler (0=CLK3, 1=CLK3/2, 2=CLK3/8, 3=Timer2compare)
+ 4-6 - Not used (0)
+ 7 TBCLK Time Base Clock (0=XOSC, 1=OSC/128) ;<-- write-able only ONCE
+
+HC05 Port 11h - TBCR2 - Time Base Control Register 2 (R/W, some bits R or W)
+ 0 COPC COP Clear 2bit COP timeout divider (0=No Change, 1=Clear) (W)
+ 1 COPE COP Enable ;<-- write-able only ONCE
+ 2 - Not used (0)
+ 3 RTBIF Reset Time Base Interrupt Flag (0=No Change, 1=Clear TBIF) (W)
+ 4-5 TBR Time Base Interrupt Rate (0=TBCLK/128, 1=/4096, 2=/8192, 3=/16384)
+ 6 TBIE Time Base Interrupt Enable (0=Disable, 1=Enable)
+ 7 TBIF Time Base Interrupt Flag (0=No, 1=IRQ) (R)
+
+HC05 Port OPTM=1:0Fh - MOSR - Mask Option Status Register (R)
+ 0-4 - Not used (0)
+ 5 XOSCR XOSC Feedback Resistor (0=None, 1=Implemented)
+ 6 OSCR OSC Feedback Resistor (0=None, 1=Implemented)
+ 7 RSTR /RESET Pullup Resistor (0=None, 1=Implemented)
+Reading this register returns A0h (on PSX/PSone with 52pin chips).
+
+==== Timer 1 ====
+
+HC05 Port 12h - TCR - Timer 1 Control Register (R/W)
+ 0 OLVL Output Level on TCMP pin on Compare Match? (0=Low, 1=High)
+ 1 IEDG Input Edge on TCAP pin (0=NegativeEdge, 1=PositiveEdge)
+ 2-4 - Not used (0)
+ 5 TOIE Timer Overflow Interrupt Enable (0=Disable, 1=Enable)
+ 6 OC1IE Output Compare Interrupt Enable (0=Disable, 1=Enable)
+ 7 ICIE Input Capture Interrupt Enable (0=Disable, 1=Enable)
+
+HC05 Port 13h - TSR - Timer 1 Status Register (R)
+ 0-4 - Not used (0)
+ 5 TOF Timer Overflow Flag (0=No, 1=Yes) (R) ;clear by Port 19h access
+ 6 OC1F Output Compare Flag (0=No, 1=Yes) (R) ;clear by Port 17h access
+ 7 ICF Input Capture Flag (0=No, 1=Yes) (R) ;clear by Port 15h access
+
+HC05 Port 14h - ICH - Timer 1 Input Capture High (undoc)
+HC05 Port 15h - ICL - Timer 1 Input Capture Low (undoc)
+ 0-15 Capture Value
+
+HC05 Port 16h - OC1H - Timer 1 Output Compare 1 High (undoc)
+HC05 Port 17h - OC1H - Timer 1 Output Compare 1 Low (undoc)
+ 0-15 Compare Value
+
+HC05 Port 18h - TCNTH - Timer 1 Counter 1 High (undoc)
+HC05 Port 19h - TCNTL - Timer 1 Counter 1 Low (undoc)
+ 0-15 Counter
+
+HC05 Port 1Ah - ACNTH - Alternate Counter High (undoc)
+HC05 Port 1Bh - ACNTL - Alternate Counter Low (undoc)
+ 0-15 Alternate Counter (uh, what?)
+
+==== Timer 2 ====
+
+HC05 Port 1Ch - TCR2 - Timer 2 Control Register (R/W)
+ 0 OL2 Timer Output 2 Edge (0=Falling, 1=Rising)
+ 1 OE2 Timer Output 2 Enable (EVO) (0=Disable, 1=Enable)
+ 2 IL2 Timer Input 2 Edge/Level (0=Low/Falling, 1=High/Rising)
+ 3 IM2 Timer Input 2 Mode Select for EVI (0=EventMode, 1=GatedByCLK2)
+ 4 T2CLK Timer 2 Clock Select (0=CLK2 from Prescaler, 1=EXCLK from EVI)
+ 5 - Not used (0)
+ 6 OC2IE Output Compare 2 Interrupt Enable (0=Disable, 1=Enable)
+ 7 TI2IE Timer Input 2 Interrupt Enable (EVI) (0=Disable, 1=Enable)
+
+HC05 Port 1Dh - TSR2 - Timer 2 Status Register (R/W)
+ 0-1 - Not used (0)
+ 2 ROC2F Reset Output Compare 2 Interrupt Flag (0=No Change, 1=Clear) (W)
+ 3 RTI2F Reset Timer Input 2 Interrupt Flag (0=No Change, 1=Clear) (W)
+ 4-5 - Not used (0)
+ 6 OC2F Output Compare 2 Interrupt Flag (0=No, 1=Yes) (R)
+ 7 TI2F Timer Input 2 Interrupt Flag (EVI) (0=No, 1=Yes) (R)
+
+HC05 Port 1Eh - OC2 - Timer 2 Output Compare Register (R/W)
+ 0-7 Compare Value ("Transferred to buffer on certain events?")
+
+HC05 Port 1Fh - TCNT2 - Timer 2 Counter Register (R) (W=Set Counter to 01h)
+ 0-7 Counter Value, incremented at T2R (set to 01h on Compare Matches)
+
+==== Reserved ====
+
+HC05 Port 3Fh - Unknown/Unused
+Reading this port via Sony's test command returns 20h (same as openbus), but
+reading it via Motorola's selftest function returns 00h (unlike openbus), so it
+seems to have some unknown/undocumented function; bit5 might indicate selftest
+mode, or it might reflect initialization of whatever other ports.
+
+HC05 Port OPTM=0:06h..07h,0Dh..0Fh - Reserved
+HC05 Port OPTM=1:01h,06h..07h,0Ch..0Dh - Reserved
+HC05 Port 20h..3Dh - Reserved
+These ports are unused/reserved. Trying to read them on a PSone does return 20h
+(possibly the prefetched next opcode value from the RAM test command). Other
+HC05 variants contain some extra features in these ports:
+--> CDROM Internal HC05 On-Chip I/O Ports - Extras
+The PSX CDROM BIOS doesn't use any of these ports - execpt, it is writing
+[20h]=2Eh (possibly to disable unused LCD hardware; which might be actually
+present in the huge 80pin HC05 chips on old PU-7 mainboards).
+
+HC05 Openbus
+Openbus values can be read from invalid memory locations, on PSX with 52pin
+chips:
+ I/O bank 0: 0:06h..07h, 0:0Dh..0Fh
+ I/O bank 1: 1:01h, 1:06h..07h, 1:0Ch..0Dh, and upper 4bit of 1:05h
+ Unbanked I/O: 20h..3Dh
+ Unused Memory: 0240h..0FFFh, 5000h..FDFFh
+The returned openbus value depends on the opcode's memory operand:
+ [nn],[mmnn],[nn+x],[mmnn+x] --> returns LAST byte of current opcode (=nn)
+ [x] --> returns FIRST byte of following opcode
+
+CDROM Internal HC05 On-Chip I/O Ports - Extras
+----------------------------------------------
+
+HC05 Port OPTM=0:0Dh - SPCR2 - Serial Peripheral Control Register 2 (R/W)
+HC05 Port OPTM=0:0Eh - SPSR2 - Serial Peripheral Status Register 2 (R)
+HC05 Port OPTM=0:0Fh - SPDR2 - Serial Peripheral Data Register 2 (R/W)
+This is a second SPI channel, works same as first SPI channel, but using the
+lower 3bits of Port G (instead of Port C) for the SPI signals.
+
+HC05 Port OPTM=0:06h - PORTG - Port G Data Register (R/W)
+HC05 Port OPTM=0:07h - PORTH - Port H Data Register (R/W)
+HC05 Port 3Ch - PORTJ - Port J Data Register (R/W)
+ PG.0 PG0 Port G Bit0 Input/Output /SDI2 (0=Low, 1=High) (R/W)
+ PG.1 PG1 Port G Bit1 Input/Output /SDO2 (0=Low, 1=High) (R/W)
+ PG.2 PG2 Port G Bit2 Input/Output /SCK2 (0=Low, 1=High) (R/W)
+ PG.3 PG3 Port G Bit3 Input/Output /TCMP (0=Low, 1=High) (R/W)
+ PG.4 PG4 Port G Bit4 Input/Output /PWM0 (0=Low, 1=High) (R/W)
+ PG.5 PG5 Port G Bit5 Input/Output /PWM1 (0=Low, 1=High) (R/W)
+ PG.6 PG6 Port G Bit6 Input/Output /PWM2 (0=Low, 1=High) (R/W)
+ PG.7 PG7 Port G Bit7 Input/Output /PWM3 (0=Low, 1=High) (R/W)
+ PH.0-7 PHn Port H Bit0..7 Input/Output (0=Low, 1=High) (R/W)
+ PJ.0-3 PJn Port J Bit0..3 Output (0=Low, 1=High) (R/W)
+ PJ.4-7 - Not used (0)
+
+HC05 Port OPTM=1:06h - DDRG - Port G Data Direction Register (R/W)
+HC05 Port OPTM=1:07h - DDRH - Port H Data Direction Register (R/W)
+ 0-7 DDRXn Port X Data Direction Bit0..7 (0=Input, 1=Output) (R/W)
+
+HC05 Port 20h - LCDCR - LCD Control Register (R/W)
+ 0 - Not used (0)
+ 1 PDH Select Port D (H) (0=FP35-FP38 pins, 1=PD7-PD4 pins)
+ 2 PEL Select Port E (L) (0=FP31-FP34 pins, 1=PE3-PE0 pins)
+ 3 PEH Select Port E (H) (0=FP27-FP30 pins, 1=PE7-PE4 pins)
+ 4 - Not used (0)
+ 5-6 DUTY LCD Duty Select (...)
+ 7 LCDE LCD Output Enable BP and FP pins (0=Disable, 1=Enable)
+
+HC05 Port 21h..34h - LCDDR1..20 - LCD Data Register 1..20 (R/W)
+ 0-3 First Data Unit ;\Fourty 4bit LCD values (in the twenty registers)
+ 4-7 Second Data Unit ;/(some duties use only the LSBs of that 4bit values)
+
+HC05 Port 34h - PWMCR - PWM Pulse Width Modulation Control Register (R/W)
+ 0-3 CH0-3 PWM Channel 0..3 on Port G.Bit4-7 Enable (0=Disable, 1=Enable)
+ 4-7 - Not used (0)
+
+HC05 Port 35h - PWMCNT - PWM Counter Register (R) (W=Set Counter to FFh)
+ 0-7 PWM Counter, incremented at PHI2 (range 01h..FFh)
+
+HC05 Port 36h - PWMDR0 - PWM Duty Register 0 (R/W)
+HC05 Port 37h - PWMDR1 - PWM Duty Register 1 (R/W)
+HC05 Port 38h - PWMDR2 - PWM Duty Register 2 (R/W)
+HC05 Port 39h - PWMDR3 - PWM Duty Register 3 (R/W)
+ 0-7 Duty (N cycles High, 255-N cycles Low)
+
+HC05 Port 3Ah - ADR - A/D Data Register (R)
+ 0-3 A/D Conversion result (probably unsigned, 00h=Lowest, FFh=Max voltage?)
+
+HC05 Port 3Bh - ADSCR - A/D Status and Control Register (R/W)
+ 0-3 CH0-3 A/D Channel (0..7=PortF.Bit0-7, 8..0Fh=Reserved/Vref/FactorTest)
+ 4 - Not used (0)
+ 5 ADON A/D Charge Pump enable (0=Disable, 1=Enable)
+ 6 ADRC A/D RC Oscillator On (0=Normal/Use CPU Clock, 1=Use RC Clock)
+ 7 COCO A/D Conversion Complete (0=Busy, 1=Complete) (R)
+
+HC05 Port 3Dh - PCR - Program Control Register (R/W) (for EPROM version)
+ 0 PGM EPROM Program Command (0=Normal, 1=Apply Programming Power)
+ 1 ELAT EPROM Latch Control (0=Normal/Read, 1=Latch/Write)
+ 2-7 RES Reserved for Factory Testing (always 0 in user mode)
+
+CDROM Internal HC05 I/O Port Usage in PSX
+-----------------------------------------
+
+Port A - Data (indexed via Port E)
+ porta.0-7 i/o CXD1815Q.Data (indexed via Port E)
+ porta.0 in debug.dta.serial.in ;\normally unused (exists in early bios)
+ porta.1 out debug.dta.serial.out ; (prototype/debug_status stuff)
+ porta.2 out debug.clk.serial.out ;/(with portc.5 = debug.select)
+
+Port B - Inputs
+ portb.0 in F-BIAS ;unused
+ portb.1 in SCEx input (serial 250 baud, received via 1000Hz timer2 irq)
+ portb.2 in LMTSW aka /POS0 ;\pos0 and door switches
+ portb.3 in DOOR aka SHELL_OPEN ;/
+ portb.4 in TEST2
+ portb.5 in TEST1 (CL316) enter test mode (instead of mainloop)
+ portb.6 in COUT ;<-- unused, extra pin, not "SENSE=COUT"
+ portb.7 in CXD2510Q.SENSE ;-from CXD2510Q (and forwarded from CXA1782BR)
+
+Port C - Inputs/Outputs
+ portc.0 in CXD2510Q.SUBQ ;\
+ portc.1 in? NC (SPI.OUT) ; used via SPDR1 to receive SPI bus SUBQ data
+ portc.2 out CXD2510Q.SQCK ;/
+ portc.3 out SPEED
+ portc.4 out ="SPEED XOR 1" ... AL/TE ... or CG ... or MIRR ?
+ portc.5 out ROMSEL: debug.select (or "SCLK" on later boards???)
+ portc.6 in CXD1815Q.XINT/IRQ2 ;unused (instead INTSTS bits are polled)
+ portc.7 in CXD2510Q.SCOR/IRQ1 ;used via polling INTSR.7 (not as irq)
+
+Port D - Outputs
+ portd.0 out NC ;-unused (always 1)
+ portd.1 out CXD2510Q.DATA ;\serial bus for CXD2510Q
+ portd.2 out CXD2510Q.XLAT ; (and also forwarded to CXA1782BR)
+ portd.3 out CXD2510Q.CLOK ;/
+ portd.4 out CXD1815Q.DECCS ;\
+ portd.5 out CXD1815Q.DECWR ; control for data/index on Port A/E
+ portd.6 out CXD1815Q.DECRD ;/
+ portd.7 out LDON ... IC723.Pin11 ... maybe "laser on" ?
+
+Port E - Index (for data on Port A)
+ porte.0-4 out CXD1815Q.Index (for data on Port A)
+ porte.5 out NC, not used
+ porte.6 out NC, see "idx_4xh" maybe test signal ???
+ porte.7 out? NC, TEST? configured as OUTPUT... but used as INPUT?
+
+Port F - Motorola Bootstrap Serial I/O (not used in cdrom bios)
+ portf.0 out NC, TX ;\
+ portf.1 in NC, RX ; not used by sony's cdrom bios
+ portf.2 out NC, RTS ; (but used by motorola's bootstrap rom)
+ portf.3 out NC, DTR ;/
+ portf.0 in Serial Data In (from daughterboard) ;\
+ portf.1 out Serial Data Out (to daughterboard) ; usage in SCPH-5903
+ portf.2 out Serial Clock Out (to daughterboard) ; (PSX with Video CD)
+ portf.3 out Audio/Video Select (0=Normal, 1=VCD) ;/
+ portf.4-7 - NC, not used (probably pins don't even exist)
+
+Other HC05 I/O Ports
+ SPI 1 - used for receiving SUBQ (via Port C)
+ IRQ 1 - used for latching/polling SUBQ's "SCOR" (not used as interrupt)
+ IRQ 2 - connects to CXD1815Q.XINT, but isn't actually used at all
+ Timer 1 - unused
+ Timer 2 - generates 1000Hz interrupts (for 250 baud "SCEx" string transfers)
+ DDRx - data directions for Port A-F (as listed above)
+Note: The PSX has the HC05 clocked via 4.00MHz oscillator (older boards), or
+via 4.3MHz signal from SPU (newer boards); internally, the HC05 is clocked at
+half of those frequencies (ie. around 2 MHz).
+
+CDROM Internal HC05 Motorola Selftest Mode
+------------------------------------------
+
+52-pin HC05 chips (newer psx cdrom controllers)
+52-pin chips are used on LATE-PU-8 boards, and on later boards ranging from
+PU-18 up to PM-41(2).
+--> CDROM Internal HC05 Motorola Selftest Mode (52pin chips)
+
+80-pin HC05 chips (older psx cdrom controllers)
+80-pin chips are used PU-7, EARLY-PU-8, and PU-9 boards.
+--> CDROM Internal HC05 Motorola Selftest Mode (80pin chips)
+
+32-pin HC05 chips (joypad/mouse)
+Sony's Digital Joypad and Mouse are using 32pin chips (with TQFP-32 package),
+which are probably containing Motorola HC05 CPUs, too. Unknown if/how those
+chips can be switched into bootstrap/dumping modes.
+
+Pinouts
+--> Pinouts - HC05 Pinouts
+
+CDROM Internal HC05 Motorola Selftest Mode (52pin chips)
+--------------------------------------------------------
+
+Motorola Bootstrap ROM
+The Motorola MC68HC05 chips are including a small bootstrap ROM which gets
+activated upon /RESET when having two pins strapped to following levels:
+ Pin30 PortC.6 (/IRQ2) (/XINT) ----> wire to 3.5V (VCC)
+ Pin31 PortC.7 (/IRQ1) (SCOR) ----> wire to 7V (2xVCC)
+Moreover, two pins are needed on /RESET for selecting a specific test mode:
+ Pin16 PortB.0 ----> ModeSelectBit0 (0=GND, 1=3.5V)
+ Pin17 PortB.1 ----> ModeSelectBit1 (0=GND, 1=3.5V)
+The selectable four modes are:
+ Mode0: Jump to RAM Address 0040h (useless when RAM is empty)
+ Mode1: Semifunctional Selftest (useless)
+ Mode2: Upload 200h bytes to RAM & jump to 0040h (allows fast/custom dumping)
+ Mode3: Download ROM as ASCII hexdump (nice, but very slow)
+The upload/download functions are using following additional pins:
+ Pin50 PortF.0 ----> TX output (11bytes: 0Dh,0Ah," AAAA DD ")
+ Pin51 PortF.1 <---- RX input (1byte: "!" to request next 11 bytes)
+ Pin52 PortF.2 ----> RTS output or so (not needed)
+ Pin1 PortF.3 ----> DTR output or so (not needed)
+ Ground ------------ GND for RX/TX
+RX/TX are RS232-like serial signals (but using other voltages, 0=0V and
+1=3.5V). Transfer format is 8-N-1, ie. one startbit(0), 8 databits LSB first,
+no parity, one stopbit(1). Baudrate is OSC/2/208 (ie. 9616 bps for 4.000MHz, or
+10176 bps for 4.2336MHz clock derived from CXD2545Q/CXD2938Q).
+Note: Above pins may vary on some chips (namely on chips that don't have
+PortF). The pins for entering bootstrap mode (PortC in this case) should be
+described in datasheets; but transfer protocol and mode selection (PortB) and
+transmission (PortF) aren't officially documented.
+
+Mode2: Upload 200h bytes to RAM & jump to 0040h
+This mode is very simple and powerful: After /RESET, you send 200h bytes to the
+RX input (without any response on TX output), the bytes are stored at
+0040h..023Fh in RAM, and the chip jumps to 0040h after transferring the last
+byte. The uploaded program can contain a custum highspeed dumping function, or
+perform hardware tests, etc. A custom dumping function for PSX/PSone can be
+found at:
+ http://www.psxdev.net/forum/viewtopic.php?f=70&t=557
+After uploading the 200h-byte dumping function it will respond by send 4540h
+bytes (containing some ASCII string, the 16.5Kbyte ROM image, plus dumps for
+RAM and (banked) I/O port region, plus openbus tests for unused memory and I/O
+regions.
+
+Wiring for Mode2 on PSX/PSone consoles with 52-pin HC05 chips
+ .------------ pin31, PC7, SCOR, cut the connection
+ 39 | 27 to Signal Processor,
+ .-----------------. then wire Pin31 to 7.5V
+ 40 | | 26
+ | C nnnn |
+ | SC4309nnPB |
+ | G63C 185 |
+ pin50, TX <--- | | ---- pin17, PB1, SCEX, wire to 3.5V,
+ pin51, RX ---> | | for Mode2 Selection
+ 52 | O | 14
+ '-----------------'
+ 1 13
+Good places to pick 3.5V and 7.5V from nice solder pads are:
+ CN602.Pin1 = 7.5V ;\on PSX boards (with either 5pin or
+ CN602.Pin3 = 3.5V ;/ 7pin CN602 connectors)
+ IC601.Pin1 = 7.5V ;-on PSone boards (3pin 78M05 voltage regulator)
+ IC102.Pin32 = 3.5V ;-on PSone boards (32pin Main BIOS ROM chip)
+The SCOR trace on Pin31, connects to Signal Processor...
+ CXD2510Q.Pin63 (eg. on PU-8 boards) ;\
+ CXD2545Q.Pin74 (eg. on PU-18 boards) ; either one of these, depending
+ CXD1817R.Pin49 (eg. on PU-20 boards) ; on which chipset you have
+ CXD2938Q.Pin77 (eg. on PM-41 boards) ;
+ CXD2941R.Pin85 (eg. PM-41(2) boards) ;/
+cut that trace (preferably on the PCB between two vias or test points, so you
+can later repair it easily) (better don't try to lift Pin31, it breaks off
+easily)
+Note: Mode2 also requires Pin16=Low, and Pin30=High (but PSX/PSone boards
+should have those pins at that voltages anyways).
+
+Mode3: Download ROM as ASCII hexdump
+This mode is very slow and not too powerful. But it may useful if you can't get
+Mode2 working for whatever reason. Wiring for Mode3 is same as above, plus
+PortB.0=3.5V. In this mode, the chip will send one 0Dh,0Ah," AAAA DD " string
+immediately after /RESET (with 16bit address "AAAA" (initially 1000h), and 8bit
+data "DD"). Thereafter the chip will wait for incoming commands:
+ 4-digit ASCII HEX address --> change address, and return 0Dh,0Ah," AAAA DD "
+ chr(00h) --> increment address, and return 0Dh,0Ah," AAAA DD "
+ chr(07h) --> jump to current address (not so useful)
+ other characters --> same as chr(00h)
+ All digits/characters sent to RX input will produce an echo on TX output.
+Basic setup would be wiring RX to GND (the chip will treat that as infinite
+stream of start bits with chr(00h), so it will respond by sending data from
+increasing addresses automatically; the increment wraps from 4FFFh to FE00h
+(skipping the gap between Main ROM and Bootstrap ROM), and also wraps from
+FFFFh to 0000h; transfer is ultraslow: 13 characters needed per dumped byte:
+chr(00h) to chip, chr(00h) echo from chip, and 0Dh,0Ah," AAAA DD " from chip.
+
+CDROM Internal HC05 Motorola Selftest Mode (80pin chips)
+--------------------------------------------------------
+
+80pin Sony 4246xx chips
+And for anyone else planning to try this, these are the connections:
+ Pin PortC
+ 46 PC7/IRQ1 (SCOR) disconnect from PCB, then wire the pin to Vtst (7.6V)
+ 45 PC6/IRQ2 (/XINT) wire to Vdd (3.5V) (you have to solder to the pin)
+In bootstrap mode, Port A is used as follows:
+ Pin PortA DDRA Usage
+ 23 PA0 in RXD
+ 24 PA1 out TXD
+ 25 PA2 in -
+ 26 PA3 in Testmode.bit0 (GND=0, 3.5V=1)
+ 27 PA4 in Testmode.bit1 (GND=0, 3.5V=1)
+ 28 PA5 in Testmode.bit2 (GND=0, 3.5V=1)
+ 29 PA6 out RTS (don't care)
+ 30 PA7 out -
+The selectable testmodes are:
+ PA5 PA4 PA3 Effect
+ 0 x x Jump to 0040h ;\
+ 1 0 0 Test (complex) ; not so useful
+ 1 0 1 Test (simple loop) ;/
+ 1 1 0 ROM Dump 4200h bytes (plain binary, non-ASCII)
+ 1 1 1 RAM Upload 100h bytes to 0040h..013Fh, then jump to 0040h
+RX/TX are plain binary (non-ASCII), baudrate is 9600 (when using 4.000MHz
+oscillator), transfer format is 8,N,2 (aka 8,N,1 with an extra pause bit).
+
+Wiring for Upload/Download on PSX consoles with 80-pin HC05 chips
+ .------------ pin46, PC7/IRQ1, SCOR, cut & wire to 7.5V
+ |.----------- pin45, PC6/IRQ2, wire to 3.5V
+ 60 || 41
+ .-----------------.
+ 61 | o | 40
+ | Sony Computer | ,----- pin28, PA5, wire to 3.5V
+ | Entertainment | _________/ ,--- pin27, PA4, wire to 3.5V
+ | Inc. (C) E35D | ==========='---- pin26, PA3, mode select
+ | 4246xx 185 | ----> pin24, PA1, TXD (for ROM dump)
+ | | <---- pin23, PA0, RXD (for RAM upload)
+ 80 | O | 21
+ '-----------------'
+ 1 20
+Good places to pick 3.5V and 7.5V from nice solder pads are:
+ CN602.Pin1 = 7.5V ;\on PSX boards (with 7pin CN602 connectors)
+ CN602.Pin3 = 3.5V ;/
+Credits to TriMesh for finding the 80pin chip's bootstrap signals.
+
+Other 80pin chips
+DTL-H100x uses 80pin chip with onchip PROM (chip text "(M) MC68HC705L15",
+instead of "Sony [...] 4246xx"), wiring for serial dumping on that is unknown
+(the bootstrap ROM may be a little different because it should contain PROM
+burning functions). PU-9 boards boards seem to use a similar PROM (with some
+sticker on it).
+DTL-H2000 uses 80pin CXP82300 chip with socketed piggyback 32pin EPROM - that
+chip is a Sony SPC700 CPU, not a Motorola HC05 CPU. Accordingly there's no
+Motorola Bootstrap mode in it, but of course one could simply dump the EPROM
+with standard eprom utilities, but nobody did do so yet).
+
+CDROM Internal CXD1815Q Sub-CPU Configuration Registers
+-------------------------------------------------------
+
+00h - DRVIF - Drive Interface (W)
+ 0-1 "L" Reserved (should be 0)
+ 2 LSB 1st CD DSP DATA order (0=MSB first, 1=LSB first)
+ 3-4 BCK MD CD DSP Number of BCLKs per WCLK (0=16, 1=24, 2=32, 3=Reserved)
+ 5 BCK RED Strobe DATA on BLCK Edge (0=Falling Edge, 1=Rising Edge)
+ 6 LCH LOW Channel on LRCK=Low (0=Right, 1=Left)
+ 7 C2PL1st ... C2PO lower byte 1st
+
+01h - CONFIG 1 - Configuration 1 (W)
+ 0 HCLKDIS HCLK Pin Output (0=8.4672MHz, 1=Disable; Fixed Low)
+ 1 CLKDIS CLK Pin Output (0=16.9344MHz, 1=Disable; Fixed Low)
+ 2 9BITRAM SRAM Databus width (0=8bit/normal, 1=9bit)
+ 3-4 RAM SZ SRMA Address bus (0=32K, 1=64K, 2=128K, 3=Reserved)
+ 5 PRTYCTL ... Priority Control
+ 6 XSLOW Number of clock cycles per DMA cycle (0=12, 1=4) (for SRAM)
+ 7 "L" Reserved (should be 0)
+
+02h - CONFIG 2 - Configuration 2 (W)
+ 0 "L" Reserved (should be 0)
+ 1 DACODIS .... DAC Out Disable
+ 2 DAMIXEN Digital Audio Mixer Enable (0=Attentuator/Mixer for CD-DA, 1=No)
+ 3 SMBF2 Number of Sound Map Buffer Surfaces (0=Three, 1=Two)
+ 4 SPMCTL Sound Parameter Majority Control (0=?) ;\for ADPCM params
+ 5 SPECTL Sound Parameter Error Control (0=?) ;/
+ 6-7 "L" Reserved (should be 0)
+
+03h - DECCTL - Decoder Control (W)
+ 0-2 DECMD Decoder Mode (0-7)
+ 0 or 1 Decoder Disable ;-disable sector reading
+ 2 or 3 Monitor-only Mode ;\no error correction
+ 4 Write-only Mode ;/
+ 5 Real-time Correction Mode ;\with error correction
+ 6 Repeat Correction Mode ;/
+ 7 CD-DA Mode ;-audio
+ 3 AUTODIST Auto Distinction (0=Use MODESEL/FORMSEL bits, 1=Use Sector Hdr)
+ (Error Correction is done according to above MODE/FORM values)
+ 4 FORMSEL Form Select (0=FORM1, 1=FORM2) (must be 0 for MODE1)
+ 5 MODESEL Mode Select (0=MODE1, 1=MODE2)
+ 6 ECCSTR ECC Strategy (0=Normal, 1=Use Error Flags; requires 9bit SRAM)
+ 7 ENDLADR Enable Drive Last Address ...
+
+07h - CHPCTL - Chip Control (W)
+ 0 "L" Reserved (should be 0)
+ 1 DBLSPD Double Speed Mode (0=Normal, 1=Double) (init CD DSP first)
+ 2 RPSTART Repeat Correction Start (0=No, 1=Start) (automatically cleared)
+ 3 SWOPEN Sync Window Open (0=SyncControlledByIC, 1=OpenDetectionWindow)
+ 4 CD-DA CD-DA Play (0=No, 1=Playback CD-DA as audio)
+ 5 CDDAMUTE CD-DA Mute (0=Normal, 1=Mute CD-DA Audio)
+ 6 RTMUTE Real-time Mute (0=Normal, 1=Mute CDROM ADPCM)
+ 7 SMMUTE Sound Map Mute (0=Normal, 1=Mute Sound Map ADPCM)
+
+CDROM Internal CXD1815Q Sub-CPU Sector Status Registers
+-------------------------------------------------------
+
+00h - ECCSTS - ECC Status (R)
+ 0 CFORM FORM assumed by Error Correction (0=FORM1, 1=FORM2)
+ 1 CMODE MODE assumed by Error Correction (0=MODE1, 1=MODE2)
+ 2 ECCOK ECC Okay (0=Bad, 1=Okay)
+ 3 EDCOK EDC Okay (0=Bad, 1=Okay)
+ 4 CORDONE Correction Done (0=None, 1=Error occurred and was corrected)
+ 5 CORINH Correction Inhibit (0=Okay,1=AUTODIST couldn't determine MODE/FORM)
+ 6 ERINBLK Erasure in Block (0=Okay, 1=At least 1 byte is wrong & uncorrected)
+ 7 EDCALL0 EDC all-zero (0=No/EDC Exists, 1=Yes/All four EDC bytes are 00h)
+
+01h - DECSTS - Decoder Status (R)
+ 0 NOSYNC No Sync (0=Okay, 1=Sector Sync Mark Missing)
+ 1 SHRTSCT Short Sector (0=Okay, 1=Sector Sync Mark within Sector Data)
+ 2-4 - Reserved (undefined)
+ 5 RTADPBSY Real-time ADPCM Busy (0=No, 1=Busy/playback)
+ 6-7 - Reserved (undefined)
+
+02h - HDRFLG - Header/Subheader Error Flags for HDR/SHDR registers (R)
+ 0 CI Error in 4th Subheader byte (Coding Info) (0=Okay, 1=Error)
+ 1 SUBMODE Error in 3rd Subheader byte (Submode) (0=Okay, 1=Error)
+ 2 CHANNEL Error in 2nd Subheader byte (Channel) (0=Okay, 1=Error)
+ 3 FILE Error in 1st Subheader byte (File) (0=Okay, 1=Error)
+ 4 MODE Error in 4th Header byte (MODE) (0=Okay, 1=Error)
+ 5 BLOCK Error in 3rd Header byte (FF) (0=Okay, 1=Error)
+ 6 SEC Error in 2nd Header byte (SS) (0=Okay, 1=Error)
+ 7 MIN Error in 1st Header byte (MM) (0=Okay, 1=Error)
+Error flags for current sector are probably stored straight in this register
+(ie. these flags are probably available even without using 9bit SRAM).
+Or maybe not... if the chip supports receiving newer sectors during
+time-consuming error corrections... then those newer would need to be stored in
+SRAM, and would thus require 9bit SRAM for the error flags?
+
+03h - HDR - Header Bytes (R)
+ 1st read: 1st Header byte (MM)
+ 2nd read: 2nd Header byte (SS)
+ 3rd read: 3rd Header byte (FF)
+ 4th read: 4th Header byte (MODE)
+
+04h - SHDR - Subheader Bytes (R)
+ 1st read: 1st Subheader byte (File)
+ 2nd read: 2nd Subheader byte (Channel)
+ 3rd read: 3rd Subheader byte (Submode) (SM)
+ 4th read: 4th Subheader byte (Coding Info) (CI)
+The contents of the HDRFLG, HDR, SHDR registers indicate:
+ (1) The corrected value in the real-time correction or
+ repeat correction mode
+ (2) Value of the raw data from the drive in the monitor-only
+ or write-only mode
+ The CMOME? and CMODE bits (bits 1, 0) of ECCSTS indicate the FORM and MODE
+ of the sector the decoder has discriminated by the raw data from the drive.
+ Due to erroneous correction, the values of these bits may be at variance
+ with those of the HDR register MODE byte and SHDR register submode byte
+ bit5.
+
+Unknown when 1st..4th read indices are reset for HDR and SHDR (maybe on access
+to certain I/O ports, or maybe anytime when receiving a new sector), also
+unknown what happens on 5th read and up.
+
+CDROM Internal CXD1815Q Sub-CPU Address Registers
+-------------------------------------------------
+
+Drive Address -- used for storing incoming CDROM sectors in Buffer RAM
+Host Address -- used for transferring Buffer RAM to (or from) Main CPU
+ADPCM Address -- used for Real-time ADPCM audio output from Buffer RAM
+
+05h - CMADR - Drive Current Minute Address (R)
+ 0-6 CMADR Address bit10-16 (in 1Kbyte steps)
+ 7 - Reserved (undefined)
+Indicates the start address of the most recently decoded sector (called "Minute
+Address" because it points to the MM byte of the MM:SS:FF:MODE sector header).
+Normally, CMADR should be forwarded to Host:
+ HADR = (CMADR AND 7Fh)*400h+offset
+ HXFR = length OR 4000h
+Whereas, offset would be usually 00h, 04h, or 0Ch (to start reading from the
+begin of the sector, or to skip 4-byte MODE1 header, or 12-byte MODE2 header).
+And length would be usually 800h (normal data sector), or 924h (entire sector,
+excluding the leading 12 sync-bytes). Length bit14 is undocumented/reserved,
+but the PSX CDROM BIOS does set that bit for whatever reason.
+Alternately, the sector can be forwarded to the Real-time ADPCM decoder:
+ ADPMNT = (CMADR AND 7Fh) OR 80h
+
+19h - ADPMNT - ADPCM "MNT" Address (W)
+ 0-6 ADPxxx ADPCM source Address bit10-16 (in 1Kbyte-steps)
+ 7 RTADPEN Real-time ADPCM Enable (0=Disable, 1=Enable Real-time ADPCM)
+
+04h - DLADR-L, Drive Last Address, bit0-7 (W)
+05h - DLADR-M, Drive Last Address, bit8-15 (W)
+06h - DLADR-H, Drive Last Address, bit16 (W)
+ 0-16 DLADR Addr. bit0-16 ...
+ 17-23 "L" Reserved (should be 0)
+
+10h - DADRC-L - Drive Address Counter, bit0-7 (W)
+11h - DADRC-M - Drive Address Counter, bit8-15 (W)
+12h - DADRC-H - Drive Address Counter, bit16 (W)
+ 0-16 DADRC Incrementing Drive-to-Buffer Write Address, bit0-16
+ 17-23 "L" Reserved (should be 0)
+
+0Eh - DADRC-L - Drive Address Counter, Bit0-7 (R)
+0Fh - DADRC-M - Drive Address Counter, Bit8-15 (R)
+ 0-15 DADRC Address bit0-15 ;bit16 is in Port 0Bh ...
+
+0Ch - HXFR-L - Host Transfer Length, bit0-7 (W)
+0Dh - HXFR-H - Host Transfer Length, bit8-11 and stuff (W)
+ 0-11 HXFR number of data bytes, bit0-11 (0..FFFh) ...
+ 12 HADR.16 HADR bit16
+ 13 "L" Reserved (should be 0)
+ 14 "L" ?? Reserved (should be 0) ;<-- XXX but on PSX: Always 1 !?!
+ ; seems to Disable INT8 ?!!!
+ 15 DISHXFRC Disable HXFRC (0=Use HXFRC, 1=Disable, Infinite-or-Zero Len?)
+
+0Eh - HADR-L - Host Transfer Address, bit0-7 (W)
+0Fh - HADR-M - Host Transfer Address, bit8-15 (W)
+ 0-15 HADR Addr. bit0-15 ;bit16 in Port 0Dh ...
+
+0Ah - HXFRC-L - Host Transfer Remain Counter, bit0-7 (R)
+0Bh - HXFRC-H - Host Transfer Remain Counter, bit8-11, and other bits (R)
+ 0-11 HXFRC Host Transfer Counter bit0-11 (number of remaining bytes)
+ 12 HADRC bit16 ;MSB of Port 0Ch/0Dh
+ 13 DADRC bit16 ;MSB of Port 0Eh/0Fh
+ 14-15 - Reserved (undefined) (usually both bits set)
+
+0Ch - HADRC-L - Host Transfer Address Counter, bit0-7 (R)
+0Dh - HADRC-M - Host Transfer Address Counter, bit8-15 (R)
+ 0-15 HADRC Address bit0-15 ;bit16 is in Port 0Bh
+"This counter keeps the addresses which write or read the data with host
+into/from the buffer.
+When data from the host is written into the buffer or data to the host is read
+from the buffer, the HADRC value is output from MA0 to 16. HADRC is incremented
+each time one byte of data from the drive is read from the buffer (BFRD is
+high) or written into the buffer (BFWR is high)."
+
+Note
+When reading from SRAM, data seems to go through a 8-byte data fifo, the HXFRC
+(remain) and HADRC (addr) values aren't aware of that FIFO (ie. if there's data
+in the fifo, then addr will be 8 bigger and remain 8 smaller than what has
+arrived at the host).
+
+Unclear Notes
+"If sound map data is to be transferred before the data is transferred
+(immediately after the host has set the BFRD and BFWR bits (bits 7 and 6) of
+the HCHPCTL register high)":
+ 900h is loaded into HXFRC
+ and 600Ch, 6A0Ch, or 740Ch is loaded into HADRC
+ (at least, supposedly, above addresses , for cases when using 32K SRAM)
+"At any other time":
+ HADR and HXFR are loaded into HADRC and HXFRC
+Unknown what the above crap is trying to say exactly.
+"At any other time" does apparently refer to cases when transfers get started
+(whilst during transfer, the address/remain values are obviously
+increasing/decreasing).
+For sound map, theoretically, the SMEN bit should be set, but above does
+somewhat suggest that BFRD or BFWR (or actually: both BFRD and BFWR) need to be
+set...?
+
+Sector Buffer Memory Map (32Kx8 SRAM)
+ 0000h 1st Sector (at 0000h..0923h) (unused gap at 0924h..0BFFh)
+ 0C00h 2nd Sector (at 0C00h..1523h) (unused gap at 1524h..17FFh)
+ 1800h 3rd Sector (at 1800h..2123h) (unused gap at 2124h..23FFh)
+ 2400h 4th Sector (at 2400h..2D23h) (unused gap at 2D24h..2FFFh)
+ 3000h 5th Sector (at 3000h..3923h) (unused gap at 3924h..3BFFh)
+ 3C00h 6th Sector (at 3C00h..4523h) (unused gap at 4524h..47FFh)
+ 4800h 7th Sector (at 4800h..5123h) (unused gap at 5124h..53FFh)
+ 5400h 8th Sector (at 5400h..5D23h) (unused gap at 5D24h..5FFFh)
+ 6000h Soundmap ADPCM Buffer (at 600Ch..690Bh) (gaps at 6000h and 690Ch)
+ 6A00h Soundmap ADPCM Buffer (at 6A0Ch..730Bh) (gaps at 6A00h and 730Ch)
+ 7400h Soundmap ADPCM Buffer (at 740Ch..7D0Bh) (gaps at 7400h and 7D0Ch)
+ 7E00h Unknown/Unused
+
+CDROM Internal CXD1815Q Sub-CPU Misc Registers
+----------------------------------------------
+
+16h - HIFCTL - Host Interface Control (W)
+ 0-2 HINT Request Host Interrupt (INT1..INT7, or 0=None/No change)
+ 3-7 "L" Reserved (should be 0)
+
+11h - HIFSTS - Host Interface Status (R)
+ 0-2 HINTSTS Pending Host Interrupt (INT1..INT7, or 0=None/All acknowledged)
+ 3 DMABUSY DMA Busy (0=Data FIFO Empty and HXFRC=0, 1=Data Transfer Busy)
+ 4 PRMRRDY Paramter Read Ready (0=Parameter FIFO Empty, 1=Ready/Not Empty)
+ 5 RSLEMPT Result Empty (0=Response FIFO Not Empty, 1=Empty)
+ 6 RSLWRDY Result Write Ready (0=Response FIFO Full, 1=Ready/Not Full)
+ 7 BUSYSTS Command Busy Status (0=Command Not Empty, 1=Ack'ed by CLRBUSY)
+
+0Ah - CLRCTL - Clear Control (W)
+ 0 RESYNC Sync with CD DSP (0=No change, 1=Resync, eg. after speed change)
+ 1-3 "L" Reserved (should be 0)
+ 4 RTADPCLR Abort Real-time ADPCM (0=No Change, 1=Abort; when ADPMNT.7=0)
+ 5 CLRRSLT Clear Reply FIFO (0=No change, 1=Acknowledge; clear FIFO)
+ 6 CLRBUSY Acknowledge Command (0=No change, 1=Acknowledge; clear BUSYSTS)
+ 7 CHPRST Chip Reset (0=No change, 1=Do Chip Initialization)
+
+07h - INTSTS - Interrupt Status (R) - (0=No, 1=IRQ)
+09h - INTMSK - Interrupt Mask (W) - (0=Disable, 1=Enable)
+0Bh - CLRINT - Clear Interrupt Status (W) - (0=No change, 1=Clear/Ack)
+ 0 HCRISD Host Chip Reset Issued
+ 1 HSTCMND Host Command ...
+ 2 DECINT Decoder Interrupt ..
+ 3 HDMACMP Host DMA Complete . <-- PSX: used for retry ?!?!!!
+ 4 RTADPEND Real-time ADPCM end
+ 5 RSLTEMPT Result Empty
+ 6 DECTOUT Decoder Time Out
+ 7 DRVOVRN Drive Overrun
+
+12h - HSTPRM - Host Parameter (R)
+ 0-7 Param FIFO (check HIFSTS.4 to see if the FIFO is empty)
+HIFSTS.4 goes off when all bytes read.
+Said to have 8-byte FIFO in CXD1199AQ datasheet.
+But, PSX has 16-byte Parameter FIFO...!?!
+
+13h - HSTCMD - Host Command (R)
+ 0-7 Command (check INTSTS.1 or HIFSTS.7 to see if a command was sent)
+Command should be ack'ed via CLRINT.1 and CLRCTL.6.
+
+17h - RESULT - Response FIFO (W)
+ 0-7 Data (has 8-byte FIFO)
+Said to have 8-byte FIFO in CXD1199AQ datasheet.
+But, PSX has 16-byte Response FIFO...!?!
+
+08h - ADPCI - ADPCM Coding Information (R)
+ 0 S/M ADPCM Stereo/Mono (0=Mono, 1=Stereo)
+ 1 - Reserved (undefined)
+ 2 FS ADPCM Sampling Frequency (0=37.8kHz, 1=18.9kHz)
+ 3 - Reserved (undefined)
+ 4 BITLNGTH ADPCM Sample Bit Length (0=Normal/4bit, 1=8bit)
+ 5 ADPBUSY ADPCM Decoding (0=No, 1=Yes/Busy)
+ 6 EMPHASIS ADPCM Emphasis (0=Normal/Off, 1=On)
+ 7 MUTE DA Data is Muted (uh?) (0=No, 1=Yes/Muted)
+Unknown if ADPCI is affected by configurations by Main-CPU's Sound Map ADPCM or
+by Sub-CPU's Real-time ADPCM (or by both)?
+Note: Bit5,7 are semi-undocumented in the datasheet (mentioned in the ADPCI
+description, but missing in overall register summary).
+
+1Bh - RTCI - Real-time ADPCM Coding Information (W)
+ 0 S/M ADPCM Stereo/Mono (0=Mono, 1=Stereo)
+ 1 "L" Reserved (should be 0)
+ 2 FS ADPCM Sampling Frequency (0=37.8kHz, 1=18.9kHz)
+ 3 "L" Reserved (should be 0)
+ 4 BITLNGTH ADPCM Sample Bit Length (0=Normal/4bit, 1=8bit)
+ 5 "L" Reserved (should be 0)
+ 6 EMPHASIS ADPCM Emphasis (0=Normal/Off, 1=On)
+ 7 "L" Reserved (should be 0)
+
+06h,09h,10h,14h..1Fh - Reserved (R)
+ 0-7 Reserved (undefined)
+Of these, 09h and 10h are officially unused/reserved. And addresses 06h and
+14h..1Fh aren't officially mentioned to exist at all.
+Trying to read these registers on a PSone returns Data=C0h for 06h, 09h, 10h,
+15h-16h, 18h-1Fh, and Data=FFh for 14h, and Data=DEh for 17h.
+
+08h,13h-15h,18h,1Ah,1Ch-1Fh - Reserved (W)
+ 0-7 Reserved (should be 00h) (or don't write at all)
+Of these, 09h,13h-15h,18h,1Ah are officially unused/reserved. And addresses
+1Ch-1Fh aren't officially mentioned to exist at all.
+
+CDROM Internal Commands CX(0x..3x) - CXA1782BR Servo Amplifier
+--------------------------------------------------------------
+
+CXA1782BR - CX(0x) - Focus Servo Control - "FZC" FocusZeroCross at SENS pin
+ 23-20 4bit Command (00h)
+ 19 1bit FS4 Focus Servo (0=Off, 1=On)
+ 18 1bit FS3 DEFECT
+ 17 1bit FS2 Enable Focus Search Voltage (0=Off, 1=On)
+ 16 1bit FS1 Select Focus Search Voltage (0=Falling, 1=Rising)
+ 15-0 16bit Unused (don't care)
+For Focus Search: Keep FS1=on, and toggle FS2 on and off (this will generate a
+waveform, and SENS will indicate when reaching a good focus voltage).
+
+CXA1782BR - CX(1x) - Tracking/Brake/Sled - "DEFECT" at SENS pin
+ 23-20 4bit Command (01h)
+ 19 1bit TG1,TG2 ON/OFF Tracking Servo Gain Up/Normal (hmmm?)
+ 18 1bit Brake Circuit ON/OFF
+ 17-16 2bit PS Sled Kick Height (0=+/-1, 1=+/-2, 2=Undoc, 3="Don't use"?)
+ 15-0 16bit Unused (don't care)
+Note: The PSX CDROM BIOS does use the "Undoc" setting (ie. bit17=1), but the
+effect is undoc/unknown?
+Note: CX(1x) works different on CXD2545Q (some bits are moved around, and the
+"SledKickHeight" bits are renamed to "SledKickLevel" and moved to different/new
+CX(3X) commands.
+
+CXA1782BR - CX(2x) - Tracking and Sled Servo Control - "TZC" at SENS pin
+ 23-20 4bit Command (02h)
+ 19-18 2bit Tracking Control (0=Off, 1=Servo On, 2=F-Jump, 3=R-Jump) ;TM1,3,4
+ 17-16 2bit Sled Control (0=Off, 1=Servo On, 2=F-Fast, 3=R-Fast) ;TM2,5,6
+ 15-0 16bit Unused (don't care)
+
+CXA1782BR - CX(3x) - "Automatic Adjustment Comparator Output" at SENS pin
+ 23-20 4bit Command (03h)
+ 19 1bit Value to be adjusted (0=Balance, 1=Gain)
+ 18-16 3bit New Balance or Gain value (depending on above bit)
+ 15-0 16bit Unused (don't care)
+Note: CX(3x) is extended and works very different on CXD2545Q.
+
+CXA1782BR Command 4x..7x - "HIGH-Z" at SENS pin
+ N-N 4bit Command (04h..07h)
+
+CXA1782BR Command 8x..Fx - "UNSPECIFIED???" at SENS pin
+ N-N 4bit Command (08h..0Fh)
+
+Note
+The Servo Amplifier isn't directly connected to the CPU. Instead, it's
+connected as a slave device to the Signal Processor. There are two ways to
+access the Servo Amplifier:
+1) The CPU can send CX(0X..3X) commands to the Signal Processor (which will
+then forward them to the Servo Amplifier).
+2) The Signal Processor can send CX(0X..3X) commands to the Servo Amplifier
+(this happens during CX(4xxx) Auto Sequence command).
+
+CDROM Internal Commands CX(4x..Ex) - CXD2510Q Signal Processor
+--------------------------------------------------------------
+
+CXD2510Q - CX(4xxx) - Auto Sequence
+ 23-20 4bit Command (4)
+ 19-16 4bit AS3-0 Auto Sequence Command (see below)
+ 15-12 4bit MT3-0 Max Timer Value (N timer units, or 0=Invalidate Timer)
+ 11 1bit LSSL Timer Units (0=2.9ms, 1=186ms) (for above MT value)
+ 10-8 3bit Unused (zero)
+ 7-0 8bit Unused (don't care)
+Values for AS (Auto Sequence Command):
+ 00h Cancel
+ 04h/05h Forward/Reverse Fine Search ;<--sends CX(25h) ;\these do internally
+ 07h Focus-On ;<--sends CX(02h) ; send commands to
+ 08h/09h Forward/Reverse 1 Track Jump ;\ ; CXA1782BR
+ 0Ah/0Bh Forward/Reverse 10 Track Jump ; sends CX(25h) ; and, auto sequence
+ 0Ch/0Dh Forward/Reverse 2N Track Jump ;/ ;/is interrupted?
+ 0Eh/0Fh Forward/Reverse 1N Track Move ;<--CXD2545Q only(Reserved on CXD2510Q)
+ 01h..03h,06h = Reserved
+
+CXD2510Q - CX(5x) - Blind,Brake,Overflow Timer
+ 23-20 4bit Command (5)
+ 19-16 4bit TR3-0 Timer (N*0.022ms for Blind/Overflow, N*0.045ms for Brake)
+ 15-8 8bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+
+CXD2510Q - CX(6xx) - SledKick,Brake,Kick Timer
+ 23-20 4bit Command (6)
+ 19-16 4bit SD3-0 Timer KICK.D (N*2.9ms for Fine Search? else N*1.45ms?)
+ 15-12 4bit KF3-0 Timer KICK.F (N*0.09ms)
+ 11-8 4bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+
+CXD2510Q - CX(7xxxx) - Track jump count setting (for Auto Sequence Command)
+ 23-20 4bit Command (7)
+ 19-4 16bit Track Jump Count Setting (0..65535) for Command 4x
+ 3-0 4bit Unused (don't care)
+
+CXD2510Q - CX(8xx) - MODE Specification
+ 23-20 4bit Command (8)
+ 19 1bit CDROM (0=Audio, 1=CDROM; no average and pre-value stuff)
+ 18 1bit DOUT Mute (0=Not muted, 1=Mute DOUT)
+ 17 1bit D.out Mute-F (0=Not muted, 1=Mute DA)
+ 16 1bit WSEL (0=Enhanced Sync Window, 1=Enhanced Anti-Rolling)
+ 15 1bit VCO SEL (0=Double Correction, 1=Quadruple Correction)
+ 14 1bit ASHS (0=Double Correction, 1=Quadruple Correction)
+ 13 1bit SOCT (0=Output SubQ to SQSO, 1=Output Each? to SQSO)
+ 12 1bit Unused (zero)
+ 11-8 4bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+
+CXD2510Q - CX(9xx) - Function Specification
+ 23-20 4bit Command (9)
+ 19 1bit DCLV ON-OFF (complex stuff, related to gain and frequencies)
+ 18 1bit DSPB ON-OFF (0=Normal Speed, 1=Double Speed; fixed pitch)
+ 17 1bit ASEQ ON-OFF (select output on SENS pin)
+ 16 1bit DPLL ON-OFF (0=Analog RFPLL, 1=Digital RFPLL)
+ 15-14 1bit Bilingual Audio (0=Stereo, 1=RightOnly, 2=LeftOnly, 3=Mute)
+ 13 1bit FLFC (normally 0)
+ 12 1bit Unused (zero)
+ 11-8 4bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+
+CXD2510Q - CX(Axx) - Audio Control
+ 23-20 4bit Command (0Ah)
+ 19 1bit Vari Up (write 1-then-0 to increase pitch by +0.1%)
+ 18 1bit Vari Down (write 1-then-0 to decrease pitch by -0.1%)
+ 17 1bit Mute (0=Not muted; unless muted elsewhere, 1=Mute & Peak=0)
+ 16 1bit ATT (0=Attentuation off, 1=Minus 12 dB)
+ 15-14 2bit PCT (0=Normal, 1=LevelMeter, 2=PeakMeter, 3=Normal) (0-1=QuadC2)
+ 13-12 2bit Unused (zero)
+ 11-8 4bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+Normal: SQSO outputs... WHAT?
+PeakMeter: SQSO outputs highest peak ever on any channel (bit15: usually 0)
+LevelMeter: SQSO outputs recent peak (with bit15 toggled: 0=Right, 1=Left)
+
+CXD2510Q - CX(Bxxxx) - Traverse Monitor Counter Setting
+ 23-20 4bit Command (0Bh)
+ 19-4 16bit Traverse Monitor Count (used when monitored by COMP and COUT) (?)
+ 3-0 4bit Unused (don't care)
+
+CXD2510Q - CX(Cxx) - Spindle Servo Coefficient Setting
+ 23-20 4bit Command (0Ch)
+ 19-18 2bit Gain MDP for CLVP mode (0=-6db, 1=0dB, 1=+6dB, 3=Reserved)
+ 17-16 2bit Gain MDS for CLVS/CLVP (0=-12dB, 1=-6dB, 2=0dB, 3=Reserved)
+ 15 1bit Zero (zero)
+ 14 1bit Gain DCLV0 overall gain (0=0dB, 1=+6dB
+ 13-12 2bit Unused (zero)
+ 11-8 4bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+
+CXD2510Q - CX(Dx) - CLV Control
+ 23-20 4bit Command (0Dh)
+ 19 1bit DCLV PWM MD Digital CLV PWM mode (0=Use MDS+MDP, 1=Ternary MDP)
+ 18 1bit TB Bottom Hold in CLVS/CLVH modes (0=At cycle RFCK/32, 1=RFCK/16)
+ 17 1bit TP Peak Hold in CLVS mode (0=At cycle RFCK/4, 1=RFCK/2)
+ 16 1bit Gain CLVS for CLVS mode (0=0dB, 1=+6dB)(always +6dB in CLVP mode)
+ 15-8 8bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+
+CXD2510Q - CX(Ex) - CLV Mode
+ 23-20 4bit Command (0Eh)
+ 19-16 4bit CM3-0
+ 15-8 8bit Unused (don't care on CXD2510Q, zero on CXD2545Q)
+ 7-0 8bit Unused (don't care)
+Values for CM (CLV Mode):
+ 00h Stop Spindle Motor Stop mode
+ 06h CLVA Automatic CLVS/CLVP switching mode, normally used for playback
+ 08h Kick Spindle Motor Forward rotation mode
+ 0Ah Brake Spindle Motor Reverse rotation mode
+ 0Ch CLVH Peak hold at 34kHz
+ 0Eh CLVS Rough Servo Mode, RF-PLL related
+ 0Fh CLVP PLL Servo mode
+
+N/A - CX(F) - Reserved
+ 23-0 N/A Don't use
+
+SUBQ Output
+ 80bit subq
+ 15bit peak level (lsb first) (absolute/unsigned value)
+ 1bit peak l/r flag (aka appears as "MSB" of peak level)
+L/R is toggled after each SUBQ reading, however the PSX Report mode does
+usually forward SUBQ only every 10 frames, so it stays stuck in one setting
+(but may toggle after one second; ie. every 75 frames). And, peak is reset
+after each read, so 9 of the 10 frames are lost.
+
+CXD2510Q - SENS output
+ Index ASEQ=0 ASEQ=1 ;<-- ASEQ can be set via CX(9xx)
+ 0X HighZ SEIN (FZC) ;\aka SENS output
+ 1X HighZ SEIN (A.S) ... aka DEFECT ; from CXA1782BR
+ 2X HighZ SEIN (T.Z.C) ... aka TZC ; forwarded through
+ 3X HighZ SEIN (SSTOP) ... aka Gain/Bal ;/CXD2510Q
+ 4X HighZ XBUSY
+ 5X HighZ FOK
+ 6X HighZ SEIN (HighZ)
+ AX GFS GFS
+ BX COMP COMP
+ CX COUT COUT
+ EX /OV64 /OV64
+ 7X-9X,DX,FX HighZ 0
+Whereas,
+ FZC Focus Zero Cross
+ DEFECT Defect?
+ TZC Tracking Zero Cross
+ SSTOP Gain or Balance adjust reached wanted level
+ XBUSY Low while the auto sequencer operation is busy
+ FOK High for "focus OK" (same as FOK pin)
+ GFS High when the played back frame sync is obtained with correct timing
+ COMP Measures the number of tracks set with Reg B. High when Reg B is
+ latched, low when the initial Reg B number is input by CNIN
+ COUT Measures the number of tracks set with Reg B. High when Reg B is
+ latched, toggles each time the Reg B number is input by CNIN. While
+ $44 and $45 are being executed, toggles with each CNIN 8-count
+ instead of the Reg B number
+ OV64 Low when filtered EFM signal is lengthened by 64 channel clock
+ pulses or more
+
+CDROM Internal Commands CX(0x..Ex) - CXD2545Q Servo/Signal Combo
+----------------------------------------------------------------
+
+CXD2545Q - CX(0x) and CX(2x) - same as CXA1782BR Servo Amplifier
+--> CDROM Internal Commands CX(0x..3x) - CXA1782BR Servo Amplifier
+
+CXD2545Q - CX(4x..Ex) - same as CXD2510Q Signal Processor
+--> CDROM Internal Commands CX(4x..Ex) - CXD2510Q Signal Processor
+One small difference is that the CXD2545Q supports a new "M Track Move"
+function as part of the CX(4xxx) command. And, some "don't care" bits are now
+reserved (ie. some commands need to be padded with additional leading "0"
+bits).
+
+CXD2545Q - CX(1x) - Anti Shock/Brake/Tracking Gain/Filter
+ 23-20 4bit Command (01h)
+ 19 1bit Anti Shock (0=Off, 1=On)
+ 18 1bit Brake (0=Off, 1=On)
+ 17 1bit Tracking Gain (0=Normal, 1=Up)
+ 16 1bit Tracking Gain Filter (0=Select 1, 1=Select 2)
+ 15-0 16bit Unused (don't care)
+
+CXD2545Q - CX(30..33) - Sled Kick Level
+ 23-20 4bit Command (03h)
+ 19-18 2bit Subcommand (0)
+ 17-16 2bit Sled Kick Level (0=+/-1, 1=+/-2, 2=+/-3, 3=+/-4)
+ 15-0 16bit Unused (don't care)
+
+CXD2545Q - CX(34xxxx) - Write to Coefficient RAM
+ 23-16 8bit Command (34h)
+ 15 1bit Zero (0)
+ 14-8 7bit Address (00h..4Fh = Select Coefficient K00..K4F)
+ 7-0 8bit Data (00h..FFh = New value)
+ PLUS 8bit Eight more bits on PSone (!)
+Allows to change the default preset coefficient values,
+--> CDROM Internal Coefficients (for CXD2545Q)
+
+CXD2545Q - CX(34Fxxx) - Write to Special Register
+ 23-12 12bit Command (34Fh)
+ 11-10 2bit Index (0=TRVSC, 1=FBIAS, 2=?, 3=?)
+ 9-0 10bit Data (for FBIAS: bit0=don't care)
+
+CXD2545Q - CX(35xxxx) - FOCUS SEARCH SPEED/VOLTAGE/AUTO GAIN
+ 23-16 8bit Command (35h)
+ 15-14 2bit FT Focus Search-up speed 1
+ 13-8 6bit FS Focus Search limit voltage (default 011000b) (+/-1.875V)
+ 7 1bit FTZ Focus Search-up speed 2
+ 6-0 7bit FG AGF Convergence Gain Setting (default 0101101b)
+
+CXD2545Q - CX(36xxxx) - DTZC/TRACK JUMP VOLTAGE/AUTO GAIN
+ 23-16 8bit Command (36h)
+ 15 1bit Zero (0)
+ 14 1bit DTZC DTZC Delay (0=4.25us/Default, 1=8.5us)
+ 13-8 6bit TJ Track Jump voltage (default 001110b) (+/-1.09V)
+ 7 1bit Zero (0)
+ 6-0 7bit TG AGT Convergence Gain Setting (default 0101110b)
+
+CXD2545Q - CX(37xxxx) - FZSL/SLED MOVE/Voltage/AUTO GAIN
+ 23-16 8bit Command (37h)
+ 15-14 2bit FZS XXX pg. 84
+ 13-8 6bit SM Sled Move Voltage
+ 7 1bit AGS
+ 6 1bit AGJ
+ 5 1bit AGGF
+ 4 1bit AGGT
+ 3 1bit AGV1
+ 2 1bit AGV2
+ 1 1bit AGHS
+ 0 1bit AGHT
+
+CXD2545Q - CX(38xxxx) - Level/Auto Gain/DFSW (Initialize)
+ 23-16 8bit Command (38h)
+ 15 1bit VCLM VC level measurement on/off
+ 14 1bit VCLC VC level compensation for FCS_In Register on/off
+ 13 1bit FLM Focus zero level measurement on/off
+ 12 1bit FLC0 Focus zero level compensation for FZC Register on/off
+ 11 1bit RFLM RF zero level measurement on/off
+ 10 1bit RFLC RF zero level compensation on/off
+ 9 1bit AGF Focus automatic gain adjustment on/off
+ 8 1bit AGT Tracking automatic gain adjustment on/off
+ 7 1bit DFSW Defect switch disable (1=disable defect measurement)
+ 6 1bit LKSW Lock switch (1=disable sled free-running prevention)
+ 5 1bit TBLM Traverse center measurement on/off
+ 4 1bit TCLM Tracking zero level measurement on/off
+ 3 1bit FLC1 Focus zero level compensation for FCS_In Register on/off
+ 2 1bit TLC2 Traverse center compensation on/off
+ 1 1bit TLC1 Tracking zero level compensation on/off
+ 0 1bit TLC0 VC level compensation for TRK/SLD_In register on/off
+VCLM,FLM,RFLM,TCLM are accepted every 2.9ms.
+
+CXD2545Q - CX(39xx) - Select internal RAM/Registers for serial readout
+ 23-16 8bit Command (39h)
+ 15 1bit DAC Serial data readout DAC mode on/off
+ 14-8 7bit SD Serial readout data select (see below)
+ 7-0 8bit Unused (don't care)
+Serial Readout Addresses:
+ Addr Data Content
+ 00h 8bit VC input signal
+ 01h 8bit SE input signal
+ 02h 8bit TE input signal
+ 03h 8bit FE input signal
+ 04h-07h 9bit TE AVRG register (mirrored to 04h-07h)
+ 08h-0Bh 9bit FE AVRG register (mirrored to 08h-0Bh)
+ 0Ch-0Fh 9bit VC AVRG register (mirrored to 0Ch-0Fh)
+ 12h 8bit RFDC envelope (peak)
+ 13h 8bit RFDC envelope (bottom)
+ 1Ch 9bit TRVSC register
+ 1Dh 9bit FBIAS register
+ 1Eh 8bit RFDC input signal
+ 1Fh 8bit RF AVRG register
+ 20h-3Fh 16bit Data RAM (M00-M1F)
+ 40h-7Fh 8bit Coefficient RAM (K00-K3F) (note: K40-K4F cannot be read out)
+
+CXD2545Q - CX(3Ax000) - Focus BIAS addition enable
+ 23-16 8bit Command (3Ah)
+ 15 1bit Zero (0)
+ 14 1bit FBON: FBIAS register addition (0=off, 1=Add FBIAS to FCS)
+ 13-0 14bit Zero (0)
+
+CXD2545Q - CX(3Bxxxx) - Operation for MIRR/DFCT/FOK
+ 23-16 8bit Command (3Bh)
+ 15-14 2bit SFO FOK Slice Level (...depends on SFOX)
+ 13-12 2bit SDF DFCT Slice Level (0=89mV, 1=134mV, 2=179mV, 3=224mV)
+ 11-10 2bit MAX DFCT Maximum Time (0=No Limit, 1=2ms, 2=2.36ms, 3=2.72ms)
+ 9 1bit SFOX FOK Slice Level (...depends on SFO)
+ 8 1bit BTF Bottom Hold Double-Speed Count-Up mode for MIRR (0=off)
+ 7-6 2bit D2V Peak Hold 2 for DFCT (0=22.05kHz, 1=44.1, 2=88.2, 3=176.4)
+ 5-4 2bit D1V Peak Hold 1 for DFCT (0=176.4kHz, 1=352.8, 2=705.6, 3=1411)
+ 3-0 4bit Zero (0)
+
+CXD2545Q - CX(3Cxxxx) - TZC for COUT SLCT HPTZC (Default)
+ 23-16 8bit Command (3Ch)
+ 15-0 16bit Unused (don't care)
+
+CXD2545Q - CX(3Dxxxx) - TZC for COUT SLCT DTZC
+ 23-16 8bit Command (3Dh)
+ 15-0 16bit Unused (don't care)
+
+CXD2545Q - CX(3Exxxx) - Filter
+ 23-16 8bit Command (3Eh)
+ 15-14 2bit F1NDM FCS servo filter 1st stage (1=normal, 2=down)
+ 13-12 2bit F3NUM FCS servo filter 3rd stage (1=normal, 2=up)
+ 11-10 2bit T1NDM TRK servo filter 1st stage (1=normal, 2=down)
+ 9-8 2bit T3NUM TRK servo filter 3rd stage (1=normal, 2=up)
+ 7 1bit DFIS FCS hold filter input extraction node (0=M05, 1=M04)
+ 6 1bit TLCD Mask TLC2 set by D2 of CX(38) only when FOK low
+ 5 1bit RFLP Pass signal from RFDC pin through low-pass-filter
+ 4-0 5bit Zero (0)
+
+CXD2545Q - CX(3Fxxxx) - Others
+ 23-16 8bit Command (3Fh) ... XXX pg. 89
+ 15-14 2bit Unused (0)
+ 13-12 2bit XTD
+ 11 1bit Unused (0)
+ 10-8 3bit DRR
+ 7 1bit Unused (0)
+ 6 1bit ASFG
+ 5 1bit Unused (0)
+ 4 1bit LPAS
+ 3-2 2bit SRO
+ 1-0 2bit Unused (0)
+
+CXD2545Q feedback on 39xx: see pg. 77 (eg. 390C = VC AVRG)
+XXX
+
+CXD2545Q - SENS output
+ Index ASEQ=0 ASEQ=1 Length
+ $0X Z FZC -
+ $1X Z AS -
+ $2X Z TZC -
+ $38 Z AGOK*1 -
+ $38 Z XAVEBSY*1 -
+ $30-37,$3A-3F Z SSTP -
+ $3904 Z TE Avrg Reg. 9 bit
+ $3908 Z FE Avrg Reg. 9 bit
+ $390C Z VC Avrg Reg. 9 bit
+ $391C Z TRVSC Reg. 9 bit
+ $391D Z FB Reg. 9 bit
+ $391F Z RFDC Avrg Reg. 8 bit
+ $4X Z XBUSY -
+ $5X Z FOK -
+ $6X Z 0 -
+ $AX GFS GFS -
+ $BX COMP COMP -
+ $CX COUT COUT -
+ $EX OV64 OV64 -
+ $7X-9X,DX,FX Z 0 -
+*1 $38 outputs AGOK during AGT and AGF command settings, and XAVEBSY during
+AVRG measurement.
+SSTP is output in all other cases.
+
+CDROM Internal Commands CX(0x..Ex) - CXD2938Q Servo/Signal/SPU Combo
+--------------------------------------------------------------------
+
+Most commands are same as on CXD2545Q. New/changed commands are:
+
+CXD2938Q - CX(349xxxxx) - New SCEx
+Older PSX consoles have received the "SCEx" string at 250 baud via HC05
+PortB.bit1, which allowed modchips to injected faked "SCEx" signals to that
+pin. To prevent that, the CXD2938Q contains some new 32bit commands that allow
+to receive somewhat encrypted "SCEx" strings via SPI bus. The used commands
+are:
+ CX(34910000) NewScexStopReading
+ CX(3491xy80) NewScexRandomKey(xy)
+ CX(34920000) NewScexFlushResyncOrSo
+ CX(34944A00) NewScexInitValue1
+ CX(3498C000) NewScexInitValue2
+ CX(349C1000) NewScexThis ;\inverse ;\use CX(3C2080) for COUT selection
+ CX(349D1000) NewScexThat ;/of COUT ;/
+The relevant command is NewScexRandomKey(xy) which does send a random value
+(x=01h..0Fh, and y=01h), and does then receive a 12-byte response via SPI bus
+(which is normally used to receive SUB-Q data).
+ 1st byte: Unknown/unused (normally ADR/Control) ;\these should be probably
+ 2nd byte: Unknown/unused (normally Track) ; set to some invalid values
+ 3rd byte: Unknown/unused (normally Index/Point) ;/to avoid SUB-Q confusion
+ 4th..10th byte: SCEx data or Dummy bytes (depending on xy.bit7..1)
+ 11th..12th byte: Unknown/unused (normally Audio Peak level)
+The 12-byte packet does contain one SCEx character encoded in 4th..10th byte
+corresponding to Flags in "xy" bit 7..1 (in that order):
+All bytes with Flag=1 are ORed together to compute a Character byte (those
+bytes could be all set to 53h for "S", or if more than one flag is set, it
+could be theoretically split to something like 41h and 12h).
+All bytes with Flag=0 are ORed together to compute a Dummy byte. If the
+Character byte is same as the Dummy byte, then it gets destroyed by setting
+Character=00h (to avoid that, one could set all dummies to 00h, or set one or
+more dummies to FFh, for example).
+Finally, "xy" bit0=0 indicates that the resulting character byte is inverted
+(XORed by FFh), however, the CDROM BIOS does always use bit0=1, so the
+inversion feature is never used.
+For the whole SCEx string, there must be at least one 00h byte inserted between
+each character (or some Char=Dummy mismatch, which results in Char=00h either),
+and there should be a few more 00h bytes preceeding the first character ("S").
+Note: Modchips didn't bother to reproduce that new SCEx transfers, instead they
+have simply bypassed it by injecting the 250 baud SCEx string to some analog
+lower level signal.
+
+CXD2938Q - CX(3Bxxxx) - Some Changed Bits
+Same as in older version, but initialized slightly differently: CXD2545Q used
+CX(3B2250) whilst CXD2938Q is using CX(3B7250).
+
+CXD2938Q - CX(3Cxxxx) - TzcCoutSelect with New/Changed Extra Bits
+The CXD2545Q used two 8bit commands, CX(3C) and CX(3D), for TzcOut selection,
+which are now replaced by a single 24bit command, CX(3Cxxxx), and which do
+include a new mode related to New SCEx.
+ CXD2545Q CXD2938Q
+ CX(3C) CX(3C0080) TzcCoutSelectHPTZC;\ <--formerly CX(3C)
+ - CX(3C2080) TzcCoutSelectSCEX ; <--special NewScex mode
+ CX(3D) CX(3C4080) TzcCoutSelectDTZC ;/ <--formerly CX(3D)
+
+CXD2938Q - CX(8xxxxx) - Disc Mode with New/Changed Extra Bits
+Command CX(8xx) has been 12bit wide on CXD2545Q, and is now expanded 24bit
+width (with some changed/unknown bits).
+ CXD2545Q CXD2938Q
+ CX(8180) CX(810408) MODE = Audio (CD-DA)
+ CX(8120) CX(812400) MODE = Audio (CD-DA) (manual SPI bus access)
+ CX(8980) CX(890408) MODE = CDROM (Data)
+ - CX(898000) MODE = CDROM (Data) (used on RESET)
+
+CXD2938Q - CX(9xx000) - Normal/Double Speed with New Extra Bits
+Command CX(9xx) has been 12bit wide on CXD2545Q (with bit12=reserved/zero), and
+is now expanded 24bit width (with bit12=unknown/one and bit11-0=unknown/zero).
+
+CXD2938Q - CX(Dx0000) and CX(Ex0000) - New Zero Padding
+Commands CX(Dx) and CX(Ex) have been 8bit wide on CXD2545Q, and are now
+zeropadded to 24bit width, ie. CX(Dx0000) and CX(Ex0000). Unknown if the extra
+bits are hiding any extra features. In practice, the CDROM BIOS is always
+setting them zero (except in some test commands which are accidently still
+using the old 8bit form, resulting in garbage in lower 16bits).
+
+CDROM Internal Commands CX(xx) - Notes
+--------------------------------------
+
+Serial Command Transmission (for Signal Processor and Servo Amplifier)
+Commands are sent serially LSB first via DATA,CLOK,XLAT pins: DATA+CLOK are
+used to send commands to the chip, command execution is then applied by
+dragging XLAT low for a moment.
+Commands can be up to 24bits in length, but unused LSBs (the "don't care" bits)
+can be omitted; the PSX BIOS clips the length to 8bit/16bit where possible (due
+to the LSB-first transfer order, the chip does treat the most recently
+transferred bit as MSB=bit23, and there's no need to transfer the LSBs if they
+aren't used).
+Aside from being used as command number, the four most recently transferred
+bits are also used to select SENS status feedback (for the SENS selection it
+doesn't matter if the four bits were terminated by XLAT or not).
+
+Sled Motor / Track Jumps / Tracking
+The Sled motor moves the drive head to the current read position. On a Compact
+Disc, the term "Track" does normally refer to Audio tracks (songs). But the
+drive hardware uses the terms "Track" and "Tracking" for different purposes:
+Tracking appears to refer to moving the Optics via magnets (ie. moving only the
+laser/lens, without actually moving the whole sled) (this is done for fine
+adjustments, and it seems to happen more or less automatically; emulators can
+just return increasing sectors without needing to handle special tracking
+commands).
+Track jumps refer to moving the entire Sled, one "track" is equal to one spiral
+winding (1.6 micrometers). One winding contains between 9 sectors on innermost
+windings, and 22.5 sectors on outermost windings (the PSX cdrom bios is
+translating the sector-distance to non-linear track-distance, and emulators
+must undo that translation; otherwise the sled doesn't arrive at the intended
+location; the cdrom bios will retry seeking a couple of times and eventually
+settle down at the desired location - but it will timeout if the sled emulation
+is too inaccurate).
+The PSX hardware uses two mechanisms for moving the Sled:
+Command CX(4xxx) Forward/Reverse Track Jump: allows to move the sled by
+1..131070 tracks (ie. max 210 millimeters), and the hardware does stop
+automatically after reaching the desired distance.
+Command CX(2x) Forward/Reverse Fast Sled: moves the sled continously until it
+gets stopped by another command (in this mode, software can watch the COUT
+signal, which gets toggled each "N" tracks; whereas "N" can be selected via
+Command CX(Bxxxx), which is configured to N=100h in PSX).
+The PSX cdrom bios is issuing another Fast Sled command (in opposite direction)
+after Fast Sled commands, emulators must somehow interprete this as "sled
+slowdown" (rather than as actually moving the sled in opposite direction, which
+could move the sled miles away from the target). For some reason vC1 BIOS is
+using a relative short slowdown period, whilst vC2/vC3 are using much longer
+slowdown periods (probably related to different SledKickHeight aka
+SledKickLevel settings and/or to different Sled Move Voltage settings).
+
+Focus / Gain / Balance
+The hardware includes commands for adjusting & measuring focus/gain/balance.
+Emulators can just omit that stuff, and can always signalize good operation
+(except that one should emulate failures for Disc Missing; and eventually also
+for cases like Laser=Off, or Spindle=Stopped).
+Focus does obviously refer to moving the lens up/down. Gain does probably refer
+to reflection level/laser intensity. Balance might refer to tracking
+adjustments or so.
+
+CDROM Internal Commands CX(xx) - Summary of Used CX(xx) Commands
+----------------------------------------------------------------
+
+The PSX CDROM BIOS versions vC1, vC2, and vC3 are using following CX()
+commands:
+ <--vC1--> <--vC2--> <--vC3-->
+ CXD2510Q CXD2545Q CXD2938Q
+ CX(00) CX(00) CX(00) AllFocusSwitchesOff
+ CX(02) CX(02) CX(02) FocusSearchVoltageFalling
+ CX(03) CX(03) CX(03) FocusSearchVoltageRising ;ForTestOnly
+ CX(08) CX(08) CX(08) FocusServoOn
+ CX(0C) CX(0C) CX(0C) FocusServoOnAndDefectOn ;diff.usage vC# ?
+ -----
+ CX(11) - - SledKickHeight2
+ CX(12) - - SledKickHeightInvalid
+ CX(19) - - TrackingGainAndSledKickHeight2
+ CX(1D) - - TrackingGainBrakeAndSledKickHeight2
+ CX(1E) - - TrackingGainBrakeAndSledKickHeightInvalid
+ -----
+ - CX(11) CX(11) AntiShockOff ;\
+ - CX(13) CX(13) AntiShockOffGainUp ;
+ - CX(17) CX(17) AntiShockOffGainUpBrake ;/
+ -----
+ CX(20) CX(20) CX(20) SledAndTrackingOff
+ CX(21) CX(21) CX(21) SledServoOn ;ForTestOnly
+ CX(22) CX(22) CX(22) SledFastForward
+ CX(23) CX(23) CX(23) SledFastReverse
+ CX(24) - - TrackingServoOn
+ CX(25) CX(25) CX(25) SledAndTrackingServoOn
+ - CX(26) CX(26) SledFastForwardAndTrackingServoOn
+ CX(28) CX(28) CX(28) TrackingForwardJump ;ForTestOnly
+ CX(2C) CX(2C) CX(2C) TrackingReverseJump ;ForTestOnly
+ -----
+ CX(30+n) - - BalanceAdjust(0..7)
+ CX(38+n) - - GainAdjust(0..7)
+ -----
+ - CX(30) CX(30) SetSledKickLevel1 ;\
+ - CX(31) CX(31) SetSledKickLevel2 ;
+ - CX(32) CX(32) SetSledKickLevel3 ;/
+ -----
+ - CX(3400E6) CX(3400E6) SetK00toE6hSledInputGain ;def=E0h
+ - CX(340730) CX(340730) SetK07to30hSledAutoGain ;blah ;def=30h
+ - CX(34114A) CX(34114A) SetK11to4AhFocusOutputGain ;def=32h
+ - CX(341330) CX(341330) SetK13to30hFocusAutoGain ;blah ;def=30h
+ - CX(341D6F) CX(341D6F) SetK1Dto6FhTrackingLowBoostFilterAL ;def=44h
+ - CX(341F64) CX(341F64) SetK1Fto64hTrackingLowBoostFilterBL ;def=5Eh
+ - CX(342220) CX(342220) SetK22to20hTrackingOutputGain ;def=18h
+ - CX(342330) CX(342330) SetK23to30hTrackingAutoGain ;blah ;def=30h
+ - CX(342D28) CX(342D28) SetK2Dto28hFocusGainDownOutputGain ;def=1Bh
+ - CX(343E70) CX(343E70) SetK3Eto70hTrackingGainUpOutputGain ;def=57h
+ - - CX(34910000) NewScexStopReading ;\
+ - - CX(3491x180) NewScexRandomKey(x) ;
+ - - CX(34920000) NewScexFlushResyncOrSo ; SCEX SPECIAL
+ - - CX(34944A00) NewScexInitValue1 ; see also:
+ - - CX(3498C000) NewScexInitValue2 ; CX(3C2080)
+ - - CX(349C1000) NewScexThis ;\inverse ;
+ - - CX(349D1000) NewScexThat ;/of COUT ;/
+ - CX(34F000) CX(34F000) SetTRVSCto000h
+ - CX(34Fxxx) CX(34Fxxx) SetFBIAStoNNNh
+ -----
+ - CX(3740AA) CX(3740AA) SetSMto00h ;\set SM to 0,6,7,9
+ - CX(3746AA) CX(3746AA) SetSMto06h ; (sled move voltage)
+ - CX(3747AA) CX(3747AA) SetSMto07h ; (and init several
+ - CX(3749AA) CX(3749AA) SetSMto09h ;/fixed settings)
+ -----
+ - CX(380010) CX(380010) ModeMeasureTrackingZeroLevel ;\Measure modes
+ - CX(380800) CX(380800) ModeMeasureRfZeroLevel ; (accepted
+ - CX(382000) CX(382000) ModeMeasureFocusZeroLevel ; every 2.9ms)
+ - CX(388000) CX(388000) ModeMeasureVcLevel ;/
+ - CX(38140A) CX(38140A) ModeCompensate
+ - CX(38140E) CX(38140E) ModeCompensateAndTraverseCenter
+ - CX(38148A) CX(38148A) ModeCompensateAndDefectOff
+ - CX(38148E) CX(38148E) ModeCompensateAndDefectOffTraverseCenter
+ - CX(3814AA) CX(3814AA) ModeCompensateAndStuffAndMeasureTraverse ;!
+ - CX(38150A) CX(38150A) ModeCompensateAndTrackingAutoGain
+ - CX(38150E) CX(38150E) ModeCompensateAndTrackingAutoGain
+ - CX(38160A) CX(38160A) ModeCompensateAndFocusAutoGain
+ -----
+ - CX(391E) - SenseRFDCinputSignalWithoutDAC ;\rather
+ - CX(3983) - SenseFEinputSignalWithDAC ;/unused
+ - CX(399C) - SenseTRVSCregisterWithDAC ;\only if
+ - CX(399D) - SenseFBIASregisterWithDAC ;/TEST1=LOW
+ -----
+ - CX(3A0000) CX(3A0000) FocusBiasAdditionOff ;\
+ - CX(3A4000) CX(3A4000) FocusBiasAdditionOn ;/
+ - CX(3B2250)!CX(3B7250)!InitOperationForMirrDfctFok <-- vC2/vC3 DIFF
+ - CX(3C) !!!CX(3C0080) TzcCoutSelectHPTZC;\ <--formerly CX(3C)
+ - - !!!CX(3C2080) TzcCoutSelectSCEX ; <--special NewScex mode
+ - CX(3D) !!!CX(3C4080) TzcCoutSelectDTZC ;/ <--formerly CX(3D)
+ - CX(3E0000) CX(3E0000) InitFilterBits ;\
+ - CX(3E0008) CX(3E0008) InitFilterBitsInvalid ;/
+ - CX(3F0008) CX(3F0008) InitOtherStuff ;-
+ -----
+ CX(4000) CX(4000) CX(4000) AutoSeqCancel
+ CX(4700) CX(4700) CX(4700) AutoSeqFocusOn
+ CX(4800) CX(4800) CX(4800) Forward1track
+ CX(4900) CX(4900) CX(4900) Reverse1track
+ CX(4C00) CX(4C00) CX(4C00) Forward2Ntrack
+ CX(4D00) CX(4D00) CX(4D00) Reverse2Ntrack
+ -----
+ CX(54) CX(54) CX(54) BlindBrakeOverflowTimer=4
+ CX(5A) CX(5A) CX(5A) BlindBrakeOverflowTimer=A
+ CX(6100) CX(6100) CX(6100) SledKickBrakeKickTimer
+ CX(70xxx0) CX(70xxx0) CX(70xxx0) TrackJumpCountSetting
+ CX(8180) CX(8180)!!!CX(810408) MODE = Audio (CD-DA)
+ - CX(8120)!!!CX(812400) MODE = Audio (CD-DA) (manual SPI bus access)
+ - - CX(810000/UNUSED)
+ - - CX(812000/UNUSED)
+ CX(8980) CX(8980) CX(890408) MODE = CDROM (Data)
+ - - CX(898000) MODE = CDROM (Data) (used on RESET)
+ CX(9B00) CX(9B00)!!!CX(9B1000) NormalSpeed
+ CX(9F00) CX(9F00)!!!CX(9F1000) DoubleSpeed
+ CX(A040) CX(A040) CX(A040) Attentuation Off
+ CX(A140) CX(A140) CX(A140) Attentuation -12 dB
+ CX(B01000) CX(B01000) CX(B01000) TraverseMonitorCounterSetting
+ CX(C600) CX(C600) CX(C600) SpindleServoCoefficientSetting
+ CX(D7) CX(D7) CX(D70000) ClvControl (fixed)
+ CX(E0) CX(E0) CX(E00000) SpindleMotorStop
+ - - CX(E02000) <-- aka bugged CX(E0) with CRAP=2000h
+ CX(E6) CX(E6) CX(E60000) AutomaticNormal
+ CX(E8) CX(E8) CX(E80000) SpindleMotorForward
+ - - CX(E8crap) <-- aka bugged CX(E8) with CRAP=xxxxh
+ CX(EA) CX(EA) CX(EA0000) SpindleMotorReverse
+ - - CX(EAcrap) <-- aka bugged CX(EA) with CRAP=xxxxh
+ CX(EE) CX(EE) CX(EE0000) RoughServo
+ -----
+ CX(F) CX(F) CX(F) Unused (N/A)
+ -----
+ CX(Xx) CX(Xx) CX(Xx) ;\
+ CX(Xxxx) CX(Xxxx) CX(Xxxx) ; TestCommand (cmd_19h_50h)
+ CX(Xxxxxx) CX(Xxxxxx) CX(Xxxxxx) ;
+ - - CX(Xxxxxxxx) ;/
+ - CX(Xxxxxx) CX(Xxxxxx) SerialSense, CX(Xxxx) with extra 8bit junk
+Note: for vC2, some CX(38xxxx) values may differ depending on
+"set_mid_lsb_to_140Eh".
+For vC2, CX(Dx) and CX(Ex) should be officially zero-padded to CX(Dx00) and
+CX(Ex00), but the vC2 BIOS doesn't do that, it still uses short 8bit form.
+For vC2, CX(Dx) and CX(Ex) should be apparently zero-padded to CX(Dx0000) and
+CX(Ex0000), at least, the vC3 BIOS is doing so (except on some test comannds
+that do still use the CX(Ex) short form).
+
+Used Sense Values
+ sense(30) SEIN.BAL ;vC2: SSTP
+ sense(38) SEIN.GAIN ;vC2: AGOK(AGT/AGF) or XAVEBSY(AVRG) or SSTP(else?)
+ sense(40) XBUSY (low=AutoSeqBusy)
+ sense(50) FOK (high=FokusOkay)
+ sense(A0) GFS (high=GoodFrameSync, ie. CorrectPlaybackSpeed)
+ sense(C5) COUT (toggles each 100h 'tracks') (100h=selected via CX(B01000))
+ sense(EA) /OV64 (low=EFM too long?)
+
+CDROM Internal Coefficients (for CXD2545Q)
+------------------------------------------
+
+The CXD2545Q contains Preset Coefficients in internal ROM, which are copied to
+internal Coefficient RAM shortly after Reset. CX(34xxxx) allows to change those
+RAM settings, and CX(39xxxx) allows to readout some of those values serially.
+
+CXD2545Q - Coefficient Preset Values
+ Addr Val Expl.
+ K00 E0 Sled input gain
+ K01 81 Sled low boost filter A-H
+ K02 23 Sled low boost filter A-L
+ K03 7F Sled low boost filter B-H
+ K04 6A Sled low boost filter B-L
+ K05 10 Sled output gain
+ K06 14 Focus input gain
+ K07 30 Sled auto gain
+ K08 7F Focus high cut filter A
+ K09 46 Focus high cut filter B
+ K0A 81 Focus low boost filter A-H
+ K0B 1C Focus low boost filter A-L
+ K0C 7F Focus low boost filter B-H
+ K0D 58 Focus low boost filter B-L
+ K0E 82 Focus phase compensate filter A
+ K0F 7F Focus defect hold gain
+ K10 4E Focus phase compensate filter B
+ K11 32 Focus output gain
+ K12 20 Anti shock input gain
+ K13 30 Focus auto gain
+ K14 80 HPTZC / Auto Gain High pass filter A
+ K15 77 HPTZC / Auto Gain High pass filter B
+ K16 80 Anti shock high pass filter A
+ K17 77 HPTZC / Auto Gain low pass filter B
+ K18 00 Fix (should not change this preset value)
+ K19 F1 Tracking input gain
+ K1A 7F Tracking high cut filter A
+ K1B 3B Tracking high cut filter B
+ K1C 81 Tracking low boost filter A-H
+ K1D 44 Tracking low boost filter A-L
+ K1E 7F Tracking low boost filter B-H
+ K1F 5E Tracking low boost filter B-L
+ K20 82 Tracking phase compensate filter A
+ K21 44 Tracking phase compensate filter B
+ K22 18 Tracking output gain
+ K23 30 Tracking auto gain
+ K24 7F Focus gain down high cut filter A
+ K25 46 Focus gain down high cut filter B
+ K26 81 Focus gain down low boost filter A-H
+ K27 3A Focus gain down low boost filter A-L
+ K28 7F Focus gain down low boost filter B-H
+ K29 66 Focus gain down low boost filter B-L
+ K2A 82 Focus gain down phase compensate filter A
+ K2B 44 Focus gain down defect hold gain
+ K2C 4E Focus gain down phase compensate filter B
+ K2D 1B Focus gain down output gain
+ K2E 00 Not used
+ K2F 00 Not used
+ K30 80 Fix (should not change this preset value)
+ K31 66 Anti shock low pass filter B
+ K32 00 Not used
+ K33 7F Anti shock high pass filter B-H
+ K34 6E Anti shock high pass filter B-L
+ K35 20 Anti shock filter comparate gain
+ K36 7F Tracking gain up2 high cut filter A
+ K37 3B Tracking gain up2 high cut filter B
+ K38 80 Tracking gain up2 low boost filter A-H
+ K39 44 Tracking gain up2 low boost filter A-L
+ K3A 7F Tracking gain up2 low boost filter B-H
+ K3B 77 Tracking gain up2 low boost filter B-L
+ K3C 86 Tracking gain up phase compensate filter A
+ K3D 0D Tracking gain up phase compensate filter B
+ K3E 57 Tracking gain up output gain
+ K3F 00 Not used
+ K40 04 Tracking hold filter input gain
+ K41 7F Tracking hold filter A-H
+ K42 7F Tracking hold filter A-L
+ K43 79 Tracking hold filter B-H
+ K44 17 Tracking hold filter B-L
+ K45 6D Tracking hold filter output gain
+ K46 00 Not used
+ K47 00 Not used
+ K48 02 Focus hold filter input gain
+ K49 7F Focus hold filter A-H
+ K4A 7F Focus hold filter A-L
+ K4B 79 Focus hold filter B-H
+ K4C 17 Focus hold filter B-L
+ K4D 54 Focus hold filter output gain
+ K4E 00 Not used
+ K4F 00 Not used
+
+CDROM Video CDs (VCD)
+---------------------
+
+VCDs are Video CDs with MPEG compression, yielding a playtime of 72 minutes per
+disc (whole movies usually being stored on two CDs). VCDs are popular in asia
+(as opposed to VHS tapes used in western world).
+
+VCDs on Playstation
+For the Playstation, the asian SCPH-5903 model includes a special daughterboard
+with MPEG decoding hardware for playing VCDs.
+--> CDROM - Video CD Commands
+--> Pinouts - VCD Pinouts
+Without that hardware it has been widely believed to be impossible to play VCDs
+on Playstations, although, as of 2017, it turned out that the Playstation's CPU
+and MDEC decoder are fast enough for that purpose (when skipping B-frames,
+rendering the movie in monochrome without colors, and reducing audio output to
+11kHz/mono).
+
+ISO Filesystem (Track 1)
+--> VCD ISO Basic Files (INFO, ENTRIES, AVSEQnn, ISO Filesystem)
+--> VCD ISO Playback Control PBC Files (PSD, LOT, ITEMnnnn)
+--> VCD ISO Search Files (SCANDATA, SEARCH, TRACKS, SPICONTX)
+--> VCD ISO Misc files (CAPTnn, AUDIOnn, KARINFO, PICTURES, CDI)
+
+MPEG Streams (Track 2 and up)
+--> VCD MPEG-1 Multiplex Stream
+--> VCD MPEG-1 Video Stream
+XXX MPEG-1 Macroblocks
+--> VCD MP2 Audio Stream
+
+VCD Versions & Variants
+XXX
+
+VCD ISO Basic Files (INFO, ENTRIES, AVSEQnn, ISO Filesystem)
+------------------------------------------------------------
+
+Primary Volume Descriptor (00:02:16)
+VCDs are having a standard ISO Primary Volume Descriptor, with some VCD
+specific entries:
+ 008h 32 System Identifier (always "CD-RTOS CD-BRIDGE" for VCDs)
+ 028h 32 Volume Identifier (often nonsense, eg. "" or "__" or "VolumeLabel")
+ 23Eh 128 Application Identifier ("CDI/CDI_APPL.VCD;1" or "CDI/CDI_VCD.APP;1")
+ 400h 8 CD-XA Identifying Signature ("CD-XA001" for PSX and VCD)
+There are some more differences to normal CDROMs:
+ VCDs are using MODE2 (with 800h-byte and 914h-byte sectors)
+ MPEG videos are on extra data tracks (outside of the ISO area on Track 1)
+ Files in VCD or SVCD folders use fixed sectors numbers (00:04:00 and up)
+ All 16bit/32bit values in files in VCD,SVCD,EXT,etc are BIG-ENDIAN
+Due to the fixed sector numbers, VCDs players can completely ignore the ISO
+filesystem with filenames and folders, and just address everything via sector
+numbers (though accessing files in EXT and CDI folders seem to require using
+the filesystem).
+
+VCD\INFO.VCD or SVCD\INFO.SVD (00:04:00) (800h bytes, one sector)
+ 000h 8 ID "VIDEO_CD" for VCD (or "SUPERVCD"/"HQ-VCD " for SVCD)
+ 008h 1 Version ;Version Major (01h) (or 02h for VCD 2.0)
+ 009h 1 System Profile Tag ;Version Minor (00h) (or 01h for VCD 1.1 or HQ)
+ 00Ah 16 Album ID/Desc (name in ASCII, padded with SPC) (usually empty)
+ 01Ah 2 Total Number of CDs in Album (1..N) ;\usually always 1,1 (even
+ 01Ch 2 Number of this CD in Album (1..N) ;/for movies with 2 discs)
+ 01Eh 13 PAL Flags, 98x1bit, for each Track? (0=NTSC, 1=PAL)
+ 02Bh 1 InfoStatusFlags (see below)
+ Below is usually zero-filled when not using PBC
+ 02Ch 4 Size of PSD.VCD file (or PSD.SVD?) (0=None)
+ 030h 3 First segment addr MM:SS:00 in BCD (00:02:00 ???)
+ 033h 1 Offset Multiplier for "PsdOffset" values in PSD.VCD (must be 8)
+ 034h 2 Number of ListIDs in LOT.VCD file (1..7FFFh, plus 1 in some discs)
+ 036h 2 Number of ITEMnnnn.DAT files (plus nonsense in some discs?)
+ Below is usually zero-filled (maybe exists on SVCD only?)
+ 038h 1980 SegmentContent[1..1980] (b0-1=Audio, b2-4=Video, b5=Cont, b6-7=OGT)
+ 7F4h 5*2 volume start time[0]: 5x16bit ;aka playing_time[5] in seconds (?)
+ 7FEh 2 Reserved (0)
+InfoStatusFlags at [02Bh] describes certain characteristics of the disc:
+ bit0 Reserved, must be zero
+ bit1-2 Restriction (0=No, 1..3=Restricted category 1..3) (eg. "not for kids")
+ bit3 Special Information is encoded in the pictures, uh?
+ bit4 MPEG User Data is used for Closed Caption (user_data_cc) (0=No, 1=Yes)
+ bit5 Next Disc with PBC (0=Start at ListID#1, 1=Start at ListID#2)
+ bit6 Next Disc without PBC (0=Start at Track #2, 1=Start at Track #3)
+ bit7 Extended PBC available (0=No, 1=Yes... aka EXT\PSD_X exists?)
+Note: Bit5/6 are used only if the next disc has the same Album ID (eg. the
+feature allows to skip copyright messages if the same message was already shown
+on another disc).
+First_segment_addr: The location of the first sector of the Segment Play Item
+Area [that is... the first ITEMnnnn.DAT file?], in the form mm:ss:00. Must be
+00:00:00 if PSD size is zero. If PSD size is nonzero, but no segments used:
+Usually set to 00:02:00.
+
+VCD\ENTRIES.VCD or SVCD\ENTRIES.SVD (00:04:01) (800h bytes, one sector)
+ 000h 8 ID "ENTRYVCD" for VCD and SVCD (or "ENTRYSVD" for VCD30)
+ 008h 1 Version ;\same as in INFO.VCD/SVD
+ 009h 1 System Profile Tag ;/
+ 00Ah 2 Number of Entries/Chapters (1..500)
+ 00Ch 4*500 Entry[N] (Track 02h..99h, and MM:SS:FF) (all 4 bytes in BCD)
+ 7DCh 36 Reserved (0)
+Version;
+ 0x02 --- VCD2.0
+ 0x01 --- SVCD, should be same as version in INFO.SVD
+Sys_prof_tag;
+ 0x01 if VCD1.1
+ 0x00 else
+
+MPEGAV\AVSEQnn.DAT (pointers to max 98 MPEG-1 Tracks, nn=01..98) (for VCDs)
+MPEG2\AVSEQnn.MPG (pointers to max 98 MPEG-2 Tracks, nn=01..98) (for SVCDs)
+MPEGAV\AVSEQnn.MPG (pointers to WHATEVER) (as so on some SVCDs or VCD30?)
+These filesystem entries contain pointers to the video tracks (that is, outside
+of the ISO area on Track 1).
+Commercially made SVCDs can reportedly contain 7 folders: Autorun, Data, Ext,
+Mpegav, Segment, Svcd and Vmp (ie. there's no MPEG2 folder on all SVCDs? though
+that MPEGAV folder is said to contain a .MPG file instead of .DAT file).
+
+VCD ISO Playback Control PBC Files (PSD, LOT, ITEMnnnn)
+-------------------------------------------------------
+
+Playback Control (PBC) is an optional feature that allows to define menues,
+pictures or text pages (whereas all those is internally just consisting of MPEG
+compressed bitmaps; rather than of text characters).
+Presence of the PBC feature is indicated by PSD.VCD filesize entry (in
+INFO.VCD) being nonzero. PBC seems to be supported by most VCDs (except older
+discs from around 1997), however, many VCDs are merely including a single
+PlayList entry for the movie track, without any further menues/extras.
+
+VCD\PSD.VCD or SVCD\PSD.SVD (00:04:34 and up) (max 256 sectors)
+The Descriptors in this file can be considered as being "program code". The
+program is usually stuck on "executing" the current descriptor (eg. playing a
+movie, or showing a selection menu) without automatically increasing the
+program counter. Actual program flow occurs only if the user presses a button
+(or upon selection timeouts), causing the program to "goto" to a new PsdOffset.
+And, something does probably happen upon end-of-track/item... maybe that does
+automatically trigger the Next button handler?
+ PsdPlayListDescriptor (14+2*N bytes):
+ 00h 1 Type (10h=PlayList)
+ 01h 1 Number of Items (noi) ;for Start-of-Movie and Numeric-Input?
+ 02h 2 ListID for this Descriptor (1..7FFFh)
+ 04h 2 PsdOffset for Prev button (FFFFh=Disable)
+ 06h 2 PsdOffset for Next button (FFFFh=Disable)
+ 08h 2 PsdOffset for Return/back button (FFFFh=Disable)
+ 0Ah 2 Play time in 1/15s (=max 72.8 minutes) (or 0000h=full item)
+ 0Ch 1 Delay time in "1s/10s" units after ;<-- uh, after? after what?
+ 0Dh 1 Auto pause time in "1s/10s" units (used for each item in list if
+ the auto pause flag in a sector is true) [WHAT is that? Trigger bit?]
+ 0Eh 2*N ItemID[N] ;item number (0..599 or 1000..2979)
+ Entry 0 is for "start of movie" (usually 0002h=Track 2)
+ Entry 1..N-1 is for numeric input ?
+ PsdSelectionListDescriptor (20+2*N bytes, or 36+6*N bytes):
+ 00h 1 Type (18h=SELECTION_LIST, or 1Ah=EXT_SELECTION_LIST)
+ 01h 1 Flags (bit0=SelectionArea, bit1=CommandList, bit2-7=Reserved)
+ 02h 1 nos <-- aka Number of Numeric-input selections ?
+ 03h 1 bsn <-- ?
+ 04h 2 ListID for this Descriptor (1..7FFFh)
+ 06h 2 PsdOffset for Prev button
+ 08h 2 PsdOffset for Next button
+ 0Ah 2 PsdOffset for Return/back button
+ 0Ch 2 PsdOffset for Default button (uh, what is that?)
+ 0Eh 2 PsdOffset for Timeout
+ 10h 1 totime <-- aka Timeout Time maybe? in WHAT units?
+ 11h 1 loop <-- aka ?
+ 12h 2 itemid <-- aka Item to be displayed during the selection?
+ 14h 2*N PsdOffset[N] for Numeric-input ?
+ Below only for SVCDs (with Type=18h), or for Extended VCDs (with Type=1Ah):
+ (14h+2*N) 4 Area for Prev (x1,y1,x2,y2) ;\these extra entries exist for
+ (18h+2*N) 4 Area for Next (x1,y1,x2,y2) ; SVCDs with Type=18h, and
+ (1Ch+2*N) 4 Area for Return (x1,y1,x2,y2) ; Extended VCDs with Type=1Ah
+ (20h+2*N) 4 Area for Default (x1,y1,x2,y2) ; (but do NOT exist for
+ (24h+2*N) 4*N Area[N] (x1,y1,x2,y2) ;/older VCDs with Type=18h)
+ PsdEndListDescriptor (8 bytes)
+ 00h 1 Type (1Fh=EndList)
+ 01h 1 Next_disc ;00h to stop PBC or NNh to switch to disc no NN (BCD!?)
+ 02h 2 Item (0 or 1000..2979, should be still image, eg. Change Disc pic)
+ 04h 4 Reserved (0)
+ N/A - This descriptor doesn't have a ListID (unlike as other descriptors)
+ PsdCommandListDescriptor (5+2*N bytes)
+ 00h 1 Type (20h=CommandList)
+ 01h 2 Command_count
+ 03h 2 ListID for this Descriptor (1..7FFFh)
+ 05h 2*N command[EMPTY_ARRAY_SIZE] ;uh, WHAT is a command?
+ PsdAlignmentPadding (after each list entry)
+ 00h 0..7 Padding to next 8-byte PsdOffset boundary (00h-filled)
+Delay values in "1s/10s" units (for PlayList[0Ch,0Dh]):
+ 1..60 --> wait "N" seconds
+ 61..254 --> wait "(N-60)*10+60" seconds
+ 255 --> wait infinite
+Item numbers (0..599 or 1000..2979) can be:
+ 0..1 - Play nothing
+ 2..99 - Play Track 2..99 (TOC tracks, for AVSEQnn.DAT and AUDIOnn.DAT?)
+ 100..599 - Play Entry 1..500 from table in ENTRIES file up to end of track
+ 600..999 - Reserved
+ 1000..2979 - Play SPI Segment Play Item 1..1980 (ITEMnnnn.DAT file)
+ 2980..65535 - Reserved
+PsdOffset values can be:
+ 0..N Offset within PSD.VCD file, in 8-byte units
+ FFFDh PSD_OFS_MULTI_DEF_NO_NUM ;\uh, what is that?
+ FFFEh PSD_OFS_MULTI_DEF ;/
+ FFFFh PSD_OFS_DISABLED ;-no function assigned to the button
+For whatever reason, some PsdOffsets are specified as ListID (lid), these
+ListID values must be translated to actual PsdOffset via the ListID Offset
+Table (aka LOT.VCD/LOT.SVD file).
+
+VCD\LOT.VCD or SVCD\LOT.SVD (00:04:02..33) (64Kbyte, 32 sectors)
+The ListID Offset Table (LOT) allows to translate ListIDs to PsdOffsets. The
+file is always 64Kbyte in size (unused entries should be set to FFFFh).
+The PSD.VCD file does also assign ListIDs to each descriptor (ie. instead of
+using the LOT.VCD file, one could also scan all descriptors in PSD.VCD when
+searching a specific ListID).
+ 0000h 2 Reserved (0)
+ 0002h 2*7FFFh PsdOffset[1..7FFFh] ;for ListID 1..7FFFh
+Note: ListID#1 is used as entrypoint to PSD.VCD when inserting a new disc (or
+when inserting another disc of the SAME movie, the entrypoint can be ListID#2,
+depending on the Next Disc flag in INFO.VCD).
+
+SEGMENT\ITEMnnnn.DAT (Pictures, Menu screens) (nnnn=0001..1980)
+These files contain Pictures/Menu screens referenced from PSD.VCD. The files
+seem to be stored in FORM2 sectors (not FORM1). Unknown if the files are
+located on Track 1.
+The content of the files seems to resemble short MPEG video clips (with only
+one picture frame, or eventually with a few frames for short animations,
+including audio in some cases). Still images are said to be allowed to use
+twice the resolution of MPEG videos.
+
+EXT\PSD_X.VCD or EXT\PSD_X.SVD (extended version of PSD.VCD)
+EXT\LOT_X.VCD or EXT\LOT_X.SVD (extended version of LOT.VCD)
+The "extended" files are often identical to the normal PSD/LOT files. The
+difference is that, if disc uses SelectionLists, then PSD should use the normal
+descriptor (18h), and PSD_X should use the extended descriptor (1Ah), the
+latter one seems to be intended to allow to highlight the current menu
+selection (particulary useful when using +/- buttons instead of Numeric Keypad
+input). Note: Nethertheless, Muppets from Space uses descriptor 18h in PSD_X.
+Unknown if SVCDs do really have "extended" files, too (theoretically the VCD
+extension should be a default feature for SVCDs).
+
+Playback Control Issues
+Although PBC was intended as "nice extra feature", many VCDs are containing
+faulty PSD files. In general, VCD players should either leave PBC unsupported
+(or at the very least, provide an option for disabling it).
+Red Dragon from 2003 uses extended selection lists, but crops PSD_X.VCD to the
+same filesize as PSD.VCD.
+Muppets from Space from 1999 assigns weird functions to Prev/Next buttons (Next
+wraps from Last Track to First Track, but Prev doesn't wrap from First to Last;
+default Non-PBC Prev/Next functions are more user friendly).
+Sony's SCPH-5903 console refuses to display the HH:MM:SS playback time when
+using PBC (instead it does only display a "PBC" logo).
+
+VCD ISO Search Files (SCANDATA, SEARCH, TRACKS, SPICONTX)
+---------------------------------------------------------
+
+Below files can help searching I-frames, and provide some info about the
+content of Tracks and Segments.
+Essentially, searching I-frames is possible without these files - however, if
+present, then the files may be useful in two cases: For discs with variable
+bitrates (which isn't allowed on VCDs though), and, for CDROM firmwares that
+don't support "inaccurate" seeking (like telling it to start reading anywhere
+NEAR some MM:SS:FF value, so one could skip sectors till reaching an I-frame)
+(ie. if the firmware insists on a "accurate" seek position, then it's best to
+give it a known I-frame address).
+
+Caution: Overlapping Sectors (!?!)
+Reportedly the new SVCD files TRACKS.SVD and SEARCH.DAT are on these sectors:
+ TRACKS_SVD_SECTOR = (PSD_VCD_SECTOR+1) ;aka 2nd sector in PSD.SVD?
+ SEARCH_DAT_SECTOR = (TRACKS_SVD_SECTOR+1) ;aka 3rd..Nth sector in PSD.SVD?
+If that's correct, then the files would overlap with PSD.SVD (when PSD.SVD is
+bigger than one sector), that would be weird, but possible (ie. the "PsdOffset"
+in PSD.SVD would need to "skip" the region used by those two files).
+
+EXT\SCANDATA.DAT (12+3*N bytes for VCD 2.0) (or 16+3*N+2*X+3*Y+3*Z for SVCD)
+This file fulfills much the same purpose of the SEARCH.DAT file except that
+this file is mandatory only if the System Profile Tag of the INFO.SVD file is
+0x01 (HQ-VCD) and also that it contains sector addresses also for each video
+Segment Play Items in addition to the regular MPEG tracks.
+ SCANDATA.DAT Format for VCD 2.0 (12+3*N bytes):
+ 000h 8 ID "SCAN_VCD"
+ 008h 1 Version (02h for VCD 2.0)
+ 009h 1 Reserved (0)
+ 00Ah 2 Number of scan points (in 0.5s units) (max FFFFh = ca. 9.1 hours)
+ 00Ch 3*N Scan Point[0..N-1] ;MM:SS:FF of closest I-frame
+ SCANDATA.DAT Format for SVCD (16+3*N+2*X+3*Y+3*Z bytes):
+ 000h 8 ID "SCAN_VCD"
+ 008h 1 Version (01h for SVCD)
+ 009h 1 Reserved (0)
+ 00Ah 2 scandata_count ;number of 3-byte entries in the table
+ 00Ch 2 track_count ;number of MPEG tracks on disc
+ 00Eh 2 spi_count ;number of consecutively recorded play item segments
+ ; (as opposed to the number of segment play items).
+ 010h 3*N msf_t cum_playtimes[N] ;cumulative playing time up to track N.
+ ; (track time just wraps at 99:59:74)
+ xxxh 2*X spi_indexes[X] ;Indexes into the following scandata table
+ xxxh 2 mpegtrack_start_index ;Index into the following scandata table
+ ; (where the MPEG track scan points start)
+ xxxh 3*Y The scandata table... [Y] ;8bit Track Number and 16bit Index
+ uint8_t track_num; /* Track number as in TOC
+ uint16_t table_offset; /* Index into scandata table
+ xxxh 3*Z msf_t scandata_table[Z] ;MM:SS:FF
+
+SVCD\SEARCH.DAT (13+3*N bytes)
+This file defines where the scan points are. It covers all mpeg tracks
+together. A scan point at time T is the nearest I-picture in the MPEG stream to
+the given time T. Scan points are given at every half-second for the entire
+duration of the disc.
+ 000h 8 ID "SEARCHSV"
+ 008h 1 Version (01h)
+ 009h 1 Reserved (0)
+ 00Ah 2 Number of scan points
+ 00Ch 1 Time_interval (in units of 0.5 seconds) (must be 01h)
+ 00Dh 3*N Scan Point[0..N-1] ;MM:SS:FF of closest I-frame
+Note: This SVCD file is about same as the old EXT\SCANDATA.DAT file on VCDs
+(with one extra entry for Time Interval). Whilst, SVCDs are storing some
+different stuff in EXT\SCANDATA.DAT (despite of the identical filename).
+
+SVCD\TRACKS.SVD (11+4*N bytes) (or rarely:11+5*N bytes)
+The TRACKS.SVD file contains a series of structures, one for each track, which
+indicates the track's playing time (in sectors, not actually real time) and
+contents.
+SVCD\TRACKS.SVD is a mandatory file which describes the numbers and types of
+MPEG tracks on the disc.
+ SVCD\TRACKS.SVD Format for SVCD (11+4*N bytes):
+ 000h 8 ID "TRACKSVD"
+ 008h 1 Version (01h)
+ 009h 1 Reserved (0)
+ 00Ah 1 Number of MPEG tracks (N)
+ 00Bh 3*N Track playing_time[N] (MM:SS:FF, in BCD)(in sectors, not real time)
+ 0xxh 1*N TrackContent[N] ;bit0-1=Audio,bit2-4=Video,bit5=Reserved,bit6-7=OGT
+ SVCD\TRACKS.SVD Format for VCD30 (11+5*N bytes) (some sort of SVCD-prototype):
+ 000h 8 ID "TRACKSVD"
+ 008h 1 Version (01h)
+ 009h 1 Reserved (0)
+ 00Ah 1 Number of MPEG tracks (N)
+ 00Bh 5*N Cum_Playing_time and Content (MM:SS:FF in BCD, and OGT, Audio)
+
+SVCD\SPICONTX.SVD (1000h bytes, two sectors)
+Unknown if/when/where/why this file exists, possibly only on VCD30?
+Note: The same info can be stored in INFO.SVD at offsets [038h..7F3h].
+ 0000h 8 ID "SPICONSV"
+ 0008h 1 Version (01h)
+ 0009h 1 Reserved (0)
+ 000Ah 2*1980 Segment Content[1..1980] (1st byte=OGT, 2nd byte=Audio)
+ 0F82h 126 Reserved (0)
+
+Content Flags for Segments and Tracks
+For SVCD\INFO.SVD and SVCD\TRACKS.SVD (on SVCD) these are encoded in 1 byte:
+ bit0-1 Audio characteristics:
+ 0 = No MPEG audio stream
+ 1 = One MPEG1 or MPEG2 audio stream without extension
+ 2 = Two MPEG1 or MPEG2 audio streams without extension
+ 3 = One MPEG2 multi-channel audio stream with extension
+ bit2-4 Video characteristics:
+ In TRACKS.SVD this must be 0,3,7 (no still pictures)
+ 0 = No MPEG video data
+ 1 = NTSC still picture
+ 2 = NTSC Reserved (NTSC still pic hires?)
+ 3 = NTSC motion picture
+ 4 = Reserved
+ 5 = PAL still picture
+ 6 = PAL Reserved (PAL still pic hires?)
+ 7 = PAL motion picture
+ bit5 Indicates segment is continuation of an item
+ In TRACKS.SVD this must be 0 (reserved)
+ 0 = First or only segment of item
+ 1 = Second or later segment of item
+ bit6-7 Overlay Graphics/Text (OGT):
+ 0 = No OGT substream
+ 1 = Sub-stream 0 available
+ 2 = Sub-stream 0 & 1 available
+ 3 = All OGT sub-substreams available
+For SPICONTX.SVD and SVCD\TRACKS.SVD (on VCD30) these are encoded in 2 bytes:
+ 1st byte = Audio characteristics ;\probably same values as
+ 2nd byte = Overlay Graphics/Text (OGT) ;/in above bitfields?
+
+VCD ISO Misc files (CAPTnn, AUDIOnn, KARINFO, PICTURES, CDI)
+------------------------------------------------------------
+
+EXT\CAPTnn.DAT (Closed Caption data, aka subtitles) (SVCD only?)
+VCDs with subtitles are usually/always having the subtitles encoded directly in
+the picture frames (ie. in the MPEG macroblocks, rather than using the Closed
+Caption feature).
+These CAPTnn.DAT files are intended for Closed Captions (eg. subtitles in
+different languages and/or for deaf people).
+Alternately, the "user_data_cc" flag in INFO.VCD?/INFO.SVD can indicate to
+store Closed Captions in MPEG User Data (with START_CODE=000001B2h=User Data)
+instead of in EXT\CAPTnn.DAT. Either way, the format of those Closed Captions
+is unknown.
+Moreover, Content can be flagged to have Overlay Graphics/Text (OGT), whatever
+that is: it might be related to Closed Captions.
+Note: Reportedly CAPTnn.DAT can exist on VCDs and SVCDs (although the same
+person reported that VCDs do not support subtitles, so that info sounds wrong).
+
+CDDA\AUDIOnn.DAT (pointers to uncompressed CD Audio Tracks)
+These filesystem entries contain pointers to uncompressed audio tracks tracks
+(that is, outside of the ISO area on Track 1).
+Most VCDs don't have audio tracks (though some VCDs do contain empty CDDA
+folders).
+Maybe the feature is occassionally used the other way around: Music discs
+containing VCD clips as bonus feature?
+
+KARAOKE\KARINFO.xxx (whatever)
+The KARAOKE folder exists on many VCDs (about 50%), but it's usually/always
+empty on all discs.
+Reportedly the folder can contain "KARINFO.xxx" files, but the purpose/format
+of that files is unknown.
+Reportedly there are Midi VCDs (MVCDs) for karaoke, maybe those discs have
+"KARINFO.xxx" files(?)
+
+PICTURES\*.* (whatever)
+Unknown purpose. The PICTURES folder has been spotted on one VCD (Wallace and
+Gromit), but the folder was just empty.
+
+CDI\*.* (some kind of GUI/driver for Philips CDI Players)
+The CDI folder is some relict for Philips CDI Players, it isn't used by normal
+VCD players, however, the CDI folder & files are included on most or all VCDs.
+The path/name for the CDI executable is stored at offset 23Eh in the ISO
+Primary Volume Descriptor (usually "CDI/CDI_APPL.VCD;1" or "CDI/CDI_VCD.APP;1")
+(or accidentally "CDI_CDI_VCD.APP;1" on homebrew Nero discs).
+The files in the CDI folder are usually just some standard files (without any
+customizations), however, there are some different revisions of these files:
+ Revision A (spotted on two discs from 1997 and 1999):
+ CDI_APPL.VCD 80702 bytes, 04-Mar-1996, CRC32=AE8FC5D0h ;executable
+ VCD_BACK.DYV 92572 bytes, 18-Jul-1995, CRC32=00693E5Eh ;whatever?
+ VCD_BTN.C8 93719 bytes, 18-Jul-1995, CRC32=FF0A636Ah ;whatever?
+ Revision B (spotted on a disc from 2003):
+ CDI_VCD.APP 20648 bytes, 00-Nul-0000 CRC32=DC885F70h ;executable
+ CDI_FONT.FNT 145388 bytes, 00-Nul-0000 CRC32=FB4D63F4h ;font?
+ CDI_ALL.RTF ? bytes, CRC32=? ;realtimefile?
+ CDI_BUM.RTF ? bytes, CRC32=? ;realtimefile?
+ Revision C (spotted on a disc from 2006, and homebrews from 2001 and 2017):
+ CDI_VCD.APP 102400 bytes, 00-Nul-0000 CRC32=E91E128Dh ;executable
+ CDI_VCD.CFG 193 bytes, 00-Nul-0000 CRC32=D1C6F7ADh ;config/ascii
+ CDI_TEXT.FNT 13616 bytes, 00-Nul-0000 CRC32=BDC55E86h ;font?
+ CDI_IMAG.RTF 1510028 bytes, 00-Nul-0000 CRC32=(RIFF) ;realtimefile?
+CDI_VCD.CFG is some ASCII text file (with uncommon 0Dh,0Dh,0Ah line breaks),
+the file could be customized to change things like GUI colors, but most or all
+discs seem to contain the same file with CRC32=D1C6F7ADh. Note: The CFG file is
+missing on the homebrew DemoVCD.
+CDI_IMAG.RTF is seen as 1510028 byte file under windows (that is, with a
+windows RIFF header, and with data area containing the whole 930h bytes from
+each sector; this includes the MM:SS:FF values from the sector header, so the
+RTF file may look slightly different depending on which sectors it has been
+stored on, although the files are usually exactly same apart from those
+MM:SS:FF values). Note: The RTF file is cropped to 1324220 bytes (instead of
+1510028) on the homebrew DemoVCD (apart from that, the file is same as normal).
+CDI_ALL.RTF and CDI_BUM.RTF cannot be read/copied under Windows 7 (which is
+weirdly reporting them to use an "invalid MS-DOS function"; some people also
+reported having CDI_IMAG.RTF files with similar problems). The reason is
+unknown, maybe windows doesn't fully support the CD filesystem, or some VCDs
+are violating the filesystem specs, or whatever... maybe windows is
+mis-identifying certain RTF files as Rich Text Format files and tries to
+prevent virus-infections by throwing a faked "MS-DOS" error message.
+
+VCD MPEG-1 Multiplex Stream
+---------------------------
+
+Multiplex Stream & Sector Boundaries
+The Multiplex stream is some higher level stream, intended to help to
+distinguish between Audio- and Video-streams (which are enclosed in the
+Multiplex stream). MPEG's are somewhat organized in "sectors", with sector size
+varying for normal .mpg files and VCDs:
+ VCD discs --> Sector Size = 914h bytes (the discs MODE2/FORM2 sector size)
+ .mpg files --> Sector Size = 800h bytes (regardless of physical sector size)
+Sectors are always beginning with a Multiplex Packet (and Multiplex Packets are
+never crossing sector boundaries). If the amount of video data exceeds the
+sector size, then it's split into several Multiplex packets, whereas, that may
+happen anywhere in the video stream (ie. there can be Multiplex Headers
+occurring even in the middle of Video packet).
+
+MPEG-1 Multiplex Pack (sector header) (12 bytes)
+The Pack Header is found at the begin of the stream (on VCDs, it's also found
+at the begin of each sector). The SCR values might help on identifying the
+current playback position, and, with the bitrate value, this could be also used
+to compute the distance to another position (though there are other ways to
+determine the position/bitrate, so the Pack is kinda useless).
+ 32bit PACK_START_CODE (000001BAh) ;-4byte
+ 2bit Fixed (00b for MPEG-1) (would be 01b for MPEG-2) ;\
+ 2bit Fixed (10b) ;
+ 3bit System Clock Reference, bit32-30 ;\ ;
+ 1bit Marker (1) ; System Clock Reference (SCR) ;
+ 15bit System Clock Reference, bit29-15 ; (intended Time, ; 5byte
+ 1bit Marker (1) ; in 90kHz clock cycles) ;
+ 15bit System Clock Reference, bit14-0 ;/ ;
+ 1bit Marker (1) ;/
+ 1bit Marker (1) ;\
+ 22bit Multiplex Rate (total bitrate of the stream, in 400bit/s units) ; 3byte
+ 1bit Marker (1) ;/
+
+MPEG-1 Multiplex System Header (12+N*3 bytes)(optionally)(at start of stream)
+The System Header is usally found after the first Pack at the begin of the
+stream.
+ 32bit SYSTEM_HEADER_START_CODE (000001BBh) ;\6byte
+ 16bit Header Length minus 6 (in bytes) (0006h+N*3) ;/
+ 1bit Marker (1) ;\
+ 22bit Rate bound (max multiplex rate of all packs in the stream, ; 3byte
+ 1bit Marker (1) in 400bit/s units) ;/
+ 6bit Audio Bound (max number of audio streams in this ISO stream) ;\
+ 1bit Fixed Flag (1=Fixed bitrate) ; 1byte
+ 1bit CSPS Flag (1=Constrained) ;/
+ 1bit System Audio Lock Flag XXX ;\
+ 1bit System Video Lock Flag XXX ; 1byte
+ 1bit Marker (1) ;
+ 5bit Video Bound (max number of video streams in this ISO stream) ;/
+ 8bit Reserved (FFh) ;-1byte
+Followed by N*3 bytes for the streams (each with first bit=set):
+ 8bit Stream ID (C0h..DFh=Audio, E0h..EFh=Video) ;\
+ 2bit Fixed (11b) ; 3byte
+ 1bit STD buffer scale (0=Mul128/audio, 1=Mul1024/video) ;
+ 13bit STD buffer size (largest required buffer over all packets) ;/
+Terminated by a value with first bit=cleared (eg. next 000001xxh value).
+
+MPEG-1 Multiplex Video/Audio/Special Packets (7..24 bytes, plus data)
+These packets are encapsulating the lower-level Video/Audio streams.
+ 32bit START (000001xxh BDh-BFh=Special, C0h-DFh=Audio, E0h-EFh=Video);\6byte
+ 16bit Packet Length minus 6 (in bytes) (1..18, plus data) ;/
+If (and while) next two bits are 11b (0..16 padding bytes):
+ (2bit) Fixed (11b, indicates presence of stuffing) ;\optional 0..16byte
+ (6bit) Fixed (111111b) ;/
+If next two bits are 01b (buffer size info):
+ (2bit) Fixed (01b, indicates presence of buffer size) ;\
+ (1bit) STD Buffer Scale (0=Mul128/audio, 1=Mul1024/video) ; optional 2byte
+ (13bit) STD Buffer Size (for decoding, in above scale units) ;/
+Always:
+ 2bit Fixed (00b, indicates no further stuffing/buffer info);\
+ 1bit PTS Flag (Presentation Time Stamp) ; 0.5 bytes
+ 1bit DTS Flag (Decoding Time Stamp) ;/
+If PTS Flag set:
+ (3bit) Presentation Time Stamp, bit32-30 ;\
+ (1bit) Marker (1) ; optional 4.5 bytes
+ (15bit) Presentation Time Stamp, bit29-15 ; (time when to output the
+ (1bit) Marker (1) ; the packet to audio/video
+ (15bit) Presentation Time Stamp, bit14-0 ; hardware, in 90kHz cycles)
+ (1bit) Marker (1) ;/
+If DTS Flag set (in this case PTS Flag must be also set):
+ (4bit) Fixed (0001b) ;\
+ (3bit) Decoding Time Stamp, bit32-30 ; optional 5 bytes
+ (1bit) Marker (1) ; (recommended time when
+ (15bit) Decoding Time Stamp, bit29-15 ; to decode the block,
+ (1bit) Marker (1) ; in 90kHz cycles)
+ (15bit) Decoding Time Stamp, bit14-0 ;
+ (1bit) Marker (1) ;/
+If PTS and DTS Flags are both zero:
+ (4bit) Fixed (1111b) ;-optional 0.5 bytes
+Always:
+ ... packet data bytes ;-data...(not crossing sector)
+Note: The first Multiplex Video Packet would usually start with a Sequence
+Header Code (000001B3h), and the first Multiplex Audio Packet should always
+start with an Audio Sync Word (FFFh).
+However, the size of the Multiplex packets does usually differ from the size of
+the packets in the audio/video stream, so new Multiplex Packets may occur
+anywhere in the middle of those streams (eg. in the middle of a video slice,
+the next Multiplex Video packet would then begin with the remaining slice
+bytes, rather than with a 000001xxh code; it's also possible that a Multiplex
+Audio packet gets inserted in the middle of the video slice).
+The best (or easiest) way to get continous data for the lower level streams
+might be to memcopy the data from Multiplex packets to separate Audio & Video
+buffers.
+
+MPEG-1 Multiplex End Code (4 bytes)
+ 32bit END_CODE (000001B9h) ;-4byte
+This should occur at the end of the video. On a VCD it does also occur at the
+end of each video track.
+
+VCD MPEG-1 Video Stream
+-----------------------
+
+The Video stream is part of the Multiplex stream, meaning that the Video
+packets preceeded (and interrupted) by Multiplex headers. Ie. before processing
+the Video packets, one must first extract the video snippets from the Multiplex
+stream (see previous chapter).
+
+MPEG-1 Video Sequence Header (12, 76, or 140 bytes, ie. 12+N*64)
+ 32bit SEQUENCE_HEADER_CODE (000001B3h) ;-4byte
+ 12bit Width in pixels (1..4095) ;\3byte
+ 12bit Height in pixels (1..2800, for max AFh slices) ;/
+ 4bit Aspect Ratio (01h..0Eh, see below) ;\1byte
+ 4bit Framerate (01h..08h, see below) ;/
+ 18bit Bitrate (in 400bit/s units, 3FFFFh=variable rate) ;\
+ 1bit Marker (1) ; 3byte
+ 10bit VBV (required decoding memory size, in "16 kB" units) ; +6bit
+ 1bit Constrained Parameter Flag ;/
+ 1bit Load Intra Q Matrix (0=No, use Standard Matrix, 1=Yes, Custom)
+Next 64byte only when above bit was set:
+ (64byte) Intra Quantizer Matrix (64 x 8bit, unsigned) (in zigzag order)
+ 1bit Load Non-Intra Q Matrix (0=No, use Standard Matrix, 1=Yes, Custom)
+Next 64byte only when above bit was set:
+ (64byte) Non-Intra Quantizer Matrix (64 x 8bit, unsigned) (in zigzag order)
+Aspect Ratio values:
+ 0 - ;forbidden
+ 1 1.0 ;square pixels
+ 2 0.6735 ;0.6735
+ 3 0.7031 ;16:9, 625 line, PAL
+ 4 0.7615 ;0.7615
+ 5 0.8055 ;0.8055
+ 6 0.8437 ;16:9, 525 line, NTSC
+ 7 0.8935 ;0.8935
+ 8 0.9157 ;4:3, 625 line, PAL, CCIR601
+ 9 0.9815 ;0.9815
+ 10 1.0255 ;1.0255
+ 11 1.0695 ;1.0695
+ 12 1.0950 ;4:3, 525 line, NTSC, CCIR601
+ 13 1.1575 ;1.1575
+ 14 1.2015 ;1.2015
+ 15 - ;reserved
+Frame Rate values:
+ 0 - ;forbidden
+ 1 23.976 (24000/1001) ;NTSC encapsulated film rate
+ 2 24.0 ;Standard international cinema film rate
+ 3 25.0 ;PAL video frame rate (625/50)
+ 4 29.97 (30000/1001) ;NTSC video frame rate
+ 5 30.0 ;NTSC video frame rate drop-frame (525/60)
+ 6 50.0 ;PAL double frame rate/progressive
+ 7 59.94 (60000/1001) ;NTSC double frame rate
+ 8 60.0 ;NTSC double frame rate drop-frame
+ 9-15 - ;reserved
+
+MPEG-1 Video Group of Pictures (GOP) (8 bytes) XXX...
+ 32bit GROUP_START_CODE (000001B8h)
+ 1bit Drop Frame (1=drop this frame; for reducing 30 fps to 29.97 fps)
+ 5bit Time Code Hours (0..23)
+ 6bit Time Code Minutes (0..59)
+ 1bit Marker (1)
+ 6bit Time Code Seconds (0..59)
+ 6bit Time Code Picture (0..59)
+ 1bit Closed GOP
+ 1bit Broken Link
+
+MPEG-1 Video Picture Header XXX...
+ 32bit PICTURE_START_CODE (00000100h) ;\
+ 10bit Temporal Reference (display order, 0..3FFh) ; 61bit
+ 3bit Coding Type (0=Invalid, 1=I, 2=P, 3=B, 4=D, 5-7=Reserved);
+ 16bit VBV Delay (in 90kHz cycles, FFFFh=variable bitrate) ;/
+If Coding Type is 2 or 3 (P-Frame or B-Frame):
+ (1bit) full fel forward vector (0=half pix, 1=full pix) ;\optional 4bit
+ (3bit) forward f code (0=invalid, 1..7=0..6bits) ;/
+If Coding Type is 3 (B-Frame):
+ (1bit) full backward vector ;\optional 4bit
+ (3bit) backward f code ;/
+If (and while) next bit is set:
+ (1bit) Fixed (1, indicates presence of Extra Info) ;\opt. N*9bit
+ (8bit) Extra Information ;/
+End of Extra:
+ 1bit Fixed (0, indicates no further Extra Info) ;-1bit
+ 0-7bit Padding to byte boundary (0) ;-0..7bit
+Coding Type values:
+ 0 Forbidden
+ 1 I - Intra Coded (full image)
+ 2 P - Predictive Coded (based on prev I or P frame)
+ 3 B - Bidirectionally Predictive Coded (based on prev+next I or P frame)
+ 4 D - DC Intra Coded (don't care, lowres thumbnail)
+ 5 Reserved
+ 6 Reserved
+ 7 Reserved
+
+Frame Order
+ DISPLAY ORDER:
+ I B B B P B B B P B B B P B B B I B B B P B B B P B B B P B B B ...
+ | |_______|_______| | |_______|_______|
+ | | | |
+ I-Frame P-frames I-Frame P-frames
+The B-fames require to know the next P- (or I-) frame in advance, for that
+reason, the frames are stored as "PBBB" (although being played as "BBBP"):
+ STORAGE ORDER:
+ I P B B B P B B B P B B B I B B B P B B B P B B B P B B B ...
+ | |_______|_______| | |_______|_______|
+ | | | |
+ I-Frame P-frames I-Frame P-frames
+
+MPEG-1 Video Slice
+Slices are containing the actual 16x16 pixel Macro Blocks. Usually a Slice
+contains one horizontal line - although, theoretically, it could be longer or
+shorter, ie. a slice could wrap to next line, or a line could be split into
+several slices (with the leading "MBA Increment" value greater than 1 to define
+the horizontal start offset).
+ 32bit PACK_START_CODE (000001xxh; xx=01h..AFh; vertical index) ;-4byte
+ 5bit Quantizer Scale (1..31) (may be later changed by blocks) ;-5bit
+If (and while) next bit is set:
+ (1bit) Fixed (1, indicates presence of Extra Info) ;\opt. N*9bit
+ (8bit) Extra Information ;/
+End of Extra:
+ 1bit Fixed (0, indicates no further Extra Info) ;-1bit
+If (and while) next 23bit are nonzero (ie. until next 000001xxh):
+ ... Macroblock (within horizontal line) ;...
+Final padding:
+ 0-7bit Padding to byte boundary (0) ;-0..7bit
+
+MPEG-1 Video Group/Sequence Extension Data (reserved)
+MPEG-1 Video User Data (optional)
+ 32bit START_CODE (000001B2h=User Data, 000001B5h=Extension Data) ;-4byte
+ ... data (end is signaled by presence of next 000001xxh code) ;-data
+User Data can contain Closed Captions (see flag in VCD\INFO.VCD or
+SVCD\INFO.SVD).
+User Data contains 11h-byte "Created with Nero" in some homebrew discs.
+
+MPEG-1 Video Sequence End Code (4 bytes)
+ 32bit SEQUENCE_END_CODE (000001B7h) ;-4byte
+
+
+
+
+MPEG-1 Video 4:2:0 Macroblock
+ N*11bit Macroblock_address_increase escape/stuffing codes (if any)
+ 1..11bit Macroblock_address_increase
+ 1-6bit Macroblock_type
+ 5bit Quantizer_scale
+ ... Motion_vector
+ 3-9bit Coded_block_pattern
+ ... Block(i)
+Aka...
+ Addr Incr
+ Type
+ Motion Vector
+ QScale
+ CBP
+ Block b0 (Y1)
+ Block b1 (Y2)
+ Block b2 (Y3)
+ Block b3 (Y4)
+ Block b4 (Cb)
+ Block b5 (Cr)
+
+
+VCD MP2 Audio Stream
+--------------------
+
+VCD video discs and .mpg movie files are having the MP2 Audio Stream enclosed
+in the Multiplex stream (whilst .mp2 audio files may contain raw MP2 data
+without Multiplex stream).
+
+Each MP2 frame is starting with a FFFh syncword (which is always located on a
+byte boundary). Unfortunately, the value FFFh can also occur anywhere in the
+audio data (eg. a 16bit sample with value 3FFCh).
+So, when starting mid-stream, one will need some guessing when searching a
+valid syncword. The best method is to compute the frame size (based on the
+supposed frame header), and then to check if supposed frame begins AND ends
+with a sync word. Moreover, one could check for invalid sample rate values in
+the frame header, or invalid "groupings" in the frame's data part.
+VCDs are conventionally having three audio frames encoded in one CDROM sector,
+so the first syncword can be simply found right after the multiplex packet
+header (though that might differ in some cases: VCD2.0 allows different audio
+bitrates, and a CDROM sector could be theoretically shared for Audio and Video
+data).
+
+Overall MP2 Frame Format
+ Header (32bit)
+ Optional CRC (16bit) (or 0bit if none)
+ Allocation Information
+ Scale Factor Selector Information
+ Scale Factors
+ Data
+
+MP2 Header
+ 12bit Syncword (FFFh) ;\
+ 1bit Revision (0=MPEG-2, 1=MPEG-1) ; 2 bytes
+ 2bit Layer (2=Audio LayerII) ;for VCDs ;
+ (3=LayerI, 1=LayerIII, 0=reserved) ;not on VCDs ;
+ 1bit Protection_bit (1=no crc) ;/
+ 4bit Bitrate_index (1..14) ;\
+ (0=free format, 15=reserved) ;
+ 2bit Sampling_frequency ; 1 byte
+ 1bit Padding_bit ;
+ 1bit Private_bit ;/
+ 2bit Mode ;\
+ 2bit Mode_extension (aka bound) ;
+ 1bit Copyright ; 1 byte
+ 1bit Original/home ;
+ 2bit Emphasis ;/
+
+MP2 Checksum (optional)
+ 16bit CRC
+
+Allocation Information
+Scale Factor Selector Information
+Scale Factors
+Data
+ XXX...
+
+Controllers and Memory Cards
+----------------------------
+
+Controllers/Memory Cards
+--> Controller and Memory Card I/O Ports
+--> Controller and Memory Card Misc
+--> Controller and Memory Card Signals
+--> Controller and Memory Card Multitap Adaptor
+
+Controllers
+--> Controllers - Communication Sequence
+--> Controllers - Standard Digital/Analog Controllers
+--> Controllers - Mouse
+--> Controllers - Racing Controllers
+--> Controllers - Lightguns
+--> Controllers - Configuration Commands
+--> Controllers - Vibration/Rumble Control
+--> Controllers - Analog Buttons (Dualshock2)
+--> Controllers - Dance Mats
+--> Controllers - Fishing Controllers
+--> Controllers - I-Mode Adaptor (Mobile Internet)
+--> Controllers - Keyboards
+--> Controllers - Additional Inputs
+--> Controllers - Misc
+
+Memory Cards
+--> Memory Card Read/Write Commands
+--> Memory Card Data Format
+--> Memory Card Images
+--> Memory Card Notes
+
+Pocketstation (Memory Card with built-in LCD screen and buttons)
+--> Pocketstation
+
+Pinouts
+--> Pinouts - Controller Ports and Memory-Card Ports
+
+Controller and Memory Card I/O Ports
+------------------------------------
+
+1F801040h JOY_TX_DATA (W)
+ 0-7 Data to be sent
+ 8-31 Not used
+Writing to this register starts the transfer (if, or as soon as TXEN=1 and
+JOY_STAT.2=Ready), the written value is sent to the controller or memory card,
+and, simultaneously, a byte is received (and stored in RX FIFO if JOY_CTRL.1 or
+JOY_CTRL.2 is set).
+The "TXEN=1" condition is a bit more complex: Writing to SIO_TX_DATA latches
+the current TXEN value, and the transfer DOES start if the current TXEN value
+OR the latched TXEN value is set (ie. if TXEN gets cleared after writing to
+SIO_TX_DATA, then the transfer may STILL start if the old latched TXEN value
+was set).
+
+1F801040h JOY_RX_DATA (R)
+ 0-7 Received Data (1st RX FIFO entry) (oldest entry)
+ 8-15 Preview (2nd RX FIFO entry)
+ 16-23 Preview (3rd RX FIFO entry)
+ 24-31 Preview (4th RX FIFO entry) (5th..8th cannot be previewed)
+A data byte can be read when JOY_STAT.1=1. Data should be read only via 8bit
+memory access (the 16bit/32bit "preview" feature is rather unusable, and
+usually there shouldn't be more than 1 byte in the FIFO anyways).
+
+1F801044h JOY_STAT (R)
+ 0 TX Ready Flag 1 (1=Ready/Started)
+ 1 RX FIFO Not Empty (0=Empty, 1=Not Empty)
+ 2 TX Ready Flag 2 (1=Ready/Finished)
+ 3 RX Parity Error (0=No, 1=Error; Wrong Parity, when enabled) (sticky)
+ 4 Unknown (zero) (unlike SIO, this isn't RX FIFO Overrun flag)
+ 5 Unknown (zero) (for SIO this would be RX Bad Stop Bit)
+ 6 Unknown (zero) (for SIO this would be RX Input Level AFTER Stop bit)
+ 7 /ACK Input Level (0=High, 1=Low)
+ 8 Unknown (zero) (for SIO this would be CTS Input Level)
+ 9 Interrupt Request (0=None, 1=IRQ7) (See JOY_CTRL.Bit4,10-12) (sticky)
+ 10 Unknown (always zero)
+ 11-31 Baudrate Timer (21bit timer, decrementing at 33MHz)
+
+1F801048h JOY_MODE (R/W) (usually 000Dh, ie. 8bit, no parity, MUL1)
+ 0-1 Baudrate Reload Factor (1=MUL1, 2=MUL16, 3=MUL64) (or 0=MUL1, too)
+ 2-3 Character Length (0=5bits, 1=6bits, 2=7bits, 3=8bits)
+ 4 Parity Enable (0=No, 1=Enable)
+ 5 Parity Type (0=Even, 1=Odd) (seems to be vice-versa...?)
+ 6-7 Unknown (always zero)
+ 8 CLK Output Polarity (0=Normal:High=Idle, 1=Inverse:Low=Idle)
+ 9-15 Unknown (always zero)
+
+1F80104Ah JOY_CTRL (R/W) (usually 1003h,3003h,0000h)
+ 0 TX Enable (TXEN) (0=Disable, 1=Enable)
+ 1 /JOYn Output (0=High, 1=Low/Select) (/JOYn as defined in Bit13)
+ 2 RX Enable (RXEN) (0=Normal, when /JOYn=Low, 1=Force Enable Once)
+ 3 Unknown? (read/write-able) (for SIO, this would be TX Output Level)
+ 4 Acknowledge (0=No change, 1=Reset JOY_STAT.Bits 3,9) (W)
+ 5 Unknown? (read/write-able) (for SIO, this would be RTS Output Level)
+ 6 Reset (0=No change, 1=Reset most JOY_registers to zero) (W)
+ 7 Not used (always zero) (unlike SIO, no matter of FACTOR)
+ 8-9 RX Interrupt Mode (0..3 = IRQ when RX FIFO contains 1,2,4,8 bytes)
+ 10 TX Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.0-or-2 ;Ready
+ 11 RX Interrupt Enable (0=Disable, 1=Enable) ;when N bytes in RX FIFO
+ 12 ACK Interrupt Enable (0=Disable, 1=Enable) ;when JOY_STAT.7 ;/ACK=LOW
+ 13 Desired Slot Number (0=/JOY1, 1=/JOY2) (set to LOW when Bit1=1)
+ 14-15 Not used (always zero)
+Caution: After slot selection (via Bits 1,13), one should issue a delay before
+sending the first data byte: Digital Joypads may work without delay, Dualshock
+and Mouse require at least some small delay, and older Analog Joypads require a
+huge delay (around 500 clock cycles for SCPH-1150), official kernel waits more
+than 2000 cycles (which is much more than needed).
+
+1F80104Eh JOY_BAUD (R/W) (usually 0088h, ie. circa 250kHz, when Factor=MUL1)
+ 0-15 Baudrate Reload value for decrementing Baudrate Timer
+Timer reload occurs when writing to this register, and, automatically when the
+Baudrate Timer reaches zero. Upon reload, the 16bit Reload value is multiplied
+by the Baudrate Factor (see 1F801048h.Bit0-1), divided by 2, and then copied to
+the 21bit Baudrate Timer (1F801044h.Bit11-31). The 21bit timer decreases at
+33MHz, and, it ellapses twice per bit (once for CLK=LOW and once for CLK=HIGH).
+ BitsPerSecond = (44100Hz*300h) / MIN(((Reload*Factor) AND NOT 1),1)
+The default BAUD value is 0088h (equivalent to 44h cpu cycles), and default
+factor is MUL1, so CLK pulses are 44h cpu cycles LOW, and 44h cpu cycles HIGH,
+giving it a transfer rate of circa 250kHz per bit (33MHz divided by 88h
+cycles).
+Note: The Baudrate Timer is always running; even if there's no transfer in
+progress.
+
+/IRQ7 (/ACK) Controller and Memory Card - Byte Received Interrupt
+Gets set after receiving a data byte - that only if an /ACK has been received
+from the peripheral (ie. there will be no IRQ if the peripheral fails to send
+an /ACK, or if there's no peripheral connected at all).
+ Actually, /IRQ7 means "more-data-request",
+ accordingly, it does NOT get triggered after receiving the LAST byte.
+I_STAT.7 is edge triggered (that means it can be acknowledge before or after
+acknowledging JOY_STAT.9). However, JOY_STAT.9 is NOT edge triggered (that
+means it CANNOT be acknowledged while the external /IRQ input is still low; ie.
+one must first wait until JOY_STAT.7=0, and then set JOY_CTRL.4=1) (this is
+apparently a hardware glitch; note: the LOW duration is circa 100 clock
+cycles).
+
+/IRQ10 (/IRQ) Controller - Lightpen Interrupt
+Pin8 on Controller Port. Routed directly to the Interrupt Controller (at
+1F80107xh). There are no status/enable bits in the JOY_registers (at
+1F80104xh).
+
+RX FIFO / TX FIFO Notes
+The JOY registers can hold up to 8 bytes in RX direction, and almost 2 bytes in
+TX direction (just like the SIO registers, see there for details), however,
+normally only 1 byte should be in the RX/TX registers (one shouldn't send a 2nd
+byte until /ACK is sensed, and, since the transfer CLK is dictated by the CPU,
+the amount of incoming data cannot exceed 1 byte; provided that one reads
+received response byte after each transfer).
+Unlike SIO, the JOY status register doesn't have a RX FIFO Overrun flag.
+
+General Notes
+RXEN should be usually zero (the hardware automatically enables receive when
+/JOYn is low). When RXEN is set, the next transfer causes data to be stored in
+RX FIFO even when /JOYn is high; the hardware automatically clears RXEN after
+the transfer.
+For existing joypads and memory cards, data should be always transferred as
+8bit no parity (although the JOY registers do support parity just like SIO
+registers).
+
+Plugging and Unplugging Cautions
+During plugging and unplugging, the Serial Data line may be dragged LOW for a
+moment; this may also affect other connected devices because the same Data line
+is shared for all controllers and memory cards (for example, connecting a
+joypad in slot 1 may corrupt memory card accesses in slot 2).
+Moreover, the Sony Mouse does power-up with /ACK=LOW, and stays stuck in that
+state until it is accessed at least once (by at least sending one 01h byte to
+its controller port); this will also affect other devices (as a workaround one
+should always access BOTH controller ports; even if a game uses only one
+controller, and, code that waits for /ACK=HIGH should use timeouts).
+
+Emulation Note
+After sending a byte, the Kernel waits 100 cycles or so, and does THEN
+acknowledge any old IRQ7, and does then wait for the new IRQ7. Due to that
+bizarre coding, emulators can't trigger IRQ7 immediately within 0 cycles after
+sending the byte.
+
+Controller and Memory Card Misc
+-------------------------------
+
+BIOS Functions
+Controllers can be probably accessed via InitPad and StartPad functions,
+--> BIOS Joypad Functions
+Memory cards can be accessed by the filesystem (with device names "bu00:"
+(slot1) and "bu10:" (slot2) or so). Before using that device names, it seems to
+be required to call InitCard, StartCard, and _bu_init (?).
+
+Connectors
+The PlayStation has four connectors (two controllers, two memory cards),
+ Memory Card 1 Memory Card 2
+ Controller 1 Controller 2
+The controller ports have 9 pins, the memory cards only 8 pins. However, there
+are only 10 different pins in total.
+ JOYDAT,JOYCMD,JOYCLK Data in/out/clock
+ +7.5V,+3.5V,GND Supply
+ /JOY1,/JOY2 Selects controller/memorycard 1, or controller/memorycard 2
+ /ACK Indicates that the device is ready to send more data (IRQ7)
+ /IRQ10 Lightgun (controllers only, not memory card) (IRQ10)
+Most of these pins are shared for all 4 connectors (eg. a CLK signal meant to
+be sent to one device will also arrive at the other 3 devices).
+The /JOYn signals are selecting BOTH the corresponding controller, and the
+corresponding memory card (whether it is a controller access or memory card
+access depends on the first byte transferred via the CMD line; this byte should
+be 01h=Controller, or 81h=Memory Card; or, a special case would be 21h=Yaroze
+Access Card).
+
+Data In/Out
+The data is transferred in units of bytes, via separate input and output lines.
+So, when sending byte, the hardware does simultaneously receive a response
+byte.
+One exception is the first command byte (which selects either the controller,
+or the memory card) until that byte has been sent, neither the controller nor
+memory card are selected (and so the first "response" byte should be ignored;
+probably containing more or less stable high-z levels).
+The other exception is, when you have send all command bytes, and still want to
+receive further data, then you'll need to send dummy command bytes (should be
+usually 00h) to receive the response bytes.
+
+Controller and Memory Card Signals
+----------------------------------
+
+Overview
+ ____ _____
+ /SEL |____________________________________________________________|
+ ______ ____ ____ ____ ____ _________
+ CLK |||||||| |||||||| |||||||| |||||||| ||||||||
+ _______________________________________________________________________
+ CMD X 01h XXXX 42h XXXX 00h XXXX 00h XXXX 00h XXXX
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ _____________________________________________________________
+ DAT -----XXXXXXXXXXXXX ID XXXX 5Ah XXXX key1 XXXX key2 XXXX-----
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ /ACK ---------------|_|---------|_|---------|_|---------|_|-----------------
+
+Top command. First comminucation(device check)
+ ____
+ /SEL |__________________________________________________________________
+ ______ _ _ _ _ _ _ _ __________________ _ _ _ _
+ CLK |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
+ __________ ___
+ CMD |________________________________________________| |_______
+ ____
+ DAT -----XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |___________
+ /ACK ----------------------------------------------|___|--------------------
+
+X = none, - = Hi-Z
+
+* 0x81 is memory-card, 0x01 is standard-pad at top command.
+* serial data transfer is LSB-First format.
+* data is down edged output, PSX is read at up edge in shift clock.
+* PSX expects No-connection if not returned Acknowledge less than 100 usec.
+* clock pulse is 250KHz.
+* no need Acknowledge at last data.
+* Acknowledge signal width is more than 2 usec.
+* time is 16msec between SEL from previous SEL.
+* SEL- for memory card in PAD access.
+
+Controller and Memory Card Multitap Adaptor
+-------------------------------------------
+
+SCPH-1070 (Multitap)
+The Multitap is an external adaptor that allows to connect 4 controllers, and 4
+memory cards to one controller port. When using two adaptors (one on each
+slot), up to 8 controllers and 8 memory cards can be used.
+
+Multitap Controller Access
+Normally joypad reading is done by sending this bytes to the pad:
+ 01 42 00 00 .. ;normal read
+And with the multitap, there are even two different ways how to access extra
+pads:
+ 01 42 01 00 .. ;method 1: receive special ID and data from ALL four pads
+ 0n 42 00 00 .. ;method 2: receive data from pad number "n" (1..4)
+The first method seems to be the more commonly used one (and its special ID is
+also good for detecting the multitap); see below for details.
+The second method works more like "normal" reads, among other it's allowing to
+transfer more than 4 halfwords per slot (unknown if any existing games are
+using that feature).
+The IRQ10 signal (for Konami Lightguns) is simply wired to all four slots via
+small resistors (without special logic for activating/deactivating the IRQ on
+certain slots).
+
+Multitap Controller Access, Method 1 Details
+Below LONG response is activated by sending "01h" as third command byte;
+observe that sending that byte does NOT affect the current response. Instead,
+it does request that the NEXT command shall return special data, as so:
+ Halfword 0 --> Controller ID for MultiTap (5A80h=Multitap)
+ Halfword 1..4 --> Player A (Controller ID, Buttons, Analog Inputs, if any)
+ Halfword 5..8 --> Player B (Controller ID, Buttons, Analog Inputs, if any)
+ Halfword 9..12 --> Player C (Controller ID, Buttons, Analog Inputs, if any)
+ Halfword 13..16 --> Player D (Controller ID, Buttons, Analog Inputs, if any)
+With this method, the Multitap is always sending 4 halfwords per slot (padded
+with FFFFh values for devices like Digital Joypads and Mice; which do use less
+than 4 halfwords); for empty slots it's padding all 4 halfwords with FFFFh.
+Sending the request is possible ONLY if there is a controller in Slot A (if
+controller Slot A is empty then the Slot A access aborts after the FIRST byte,
+and it's thus impossible to send the request in the THIRD byte).
+Sending the request works on access to Slot A, trying to send another request
+during the LONG response is glitchy (for whatever strange reason); one must
+thus REPEATEDLY do TWO accesses: one dummy Slot A access (with the request),
+followed by the long Slot A+B+C+D access.
+ Previous access had REQ=0 and returned Slot A data ---> returns Slot A data
+ Previous access had REQ=0 and returned Slot A-D data -> returns Slot A data
+ Previous access had REQ=1 and returned Slot A data ---> returns Slot A-D data
+ Previous access had REQ=1 and returned Slot A-D data -> returns garbage
+ Previous access had REQ=1 and returned garbage -------> returns Slot A-D data
+In practice:
+Toggling REQ on/off after each command: Returns responses toggling between
+normal Slot A data and long Slot A+B+C+D data.
+Sending REQ=1 in ALL commands: Returns responses toggling between Garbage and
+long Slot A+B+C+D data.
+Both of the above is working (one needs only the Slot A+B+C+D part, and it
+doesn't matter if the other part is Slot A, or Garbage; as long as the software
+is able/aware of ignoring the Garbage). Garbage response means that the
+multitap returns ONLY four bytes, like so: Hiz,80h,5Ah,LSB (ie. the leading
+HighZ byte, the 5A80h Multitap ID, and the LSB of the Slot A controller ID),
+and aborts transfer after that four bytes.
+
+Multitap Memory Card Access
+Normally memory card access is done by sending this bytes to the card:
+ 80 xx .. .. ;normal access
+And with the multitap, memory cards can be accessed as so:
+ 8n xx .. .. ;access memory card in slot "n" (1..4)
+That's the way how its done in Silent Hill. Although for the best of confusion,
+it doesn't actually work in that game (probably the developer has just linked
+in the multitap library, without actually supporting the multitap at higher
+program levels).
+
+Multitap Games
+ Bomberman World
+ Breakout: Off the Wall Fun
+ Circuit Breakers
+ Crash Team Racing
+ FIFA series soccer games
+ Frogger
+ Gauntlet: Dark Legacy
+ Hot Shots Golf 2 & 3
+ NBA Live (any year) (up to 8 players with two multitaps)
+ Need For Speed 3
+ Need For Speed 5
+ Poy Poy (4 players hitting each other with rocks and trees)
+ Running Wild
+
+Multitap Versions
+ .------.
+ SCPH-1070 | | SCPH-111
+ (gray case) | | (white case)
+ (for PSX) | D | (for PSone)
+ | | .----------------.
+ cable | | cable .' D C '.
+ ''--.. | C | '''--..__| |
+ \| | | |
+ .----------------' | '. A B .'
+ | | '----------------'
+ | |
+ | A B /
+ '---------------------'
+The cable connects to one of the PSX controller ports (which also carries the
+memory card signals). The PSX memory card port is left unused (and is blocked
+by a small edge on the Multitap's plug).
+
+MultiTap Parsed Controller IDs
+Halfword 0 is parsed (by the BIOS) as usually, ie. the LSB is moved to MSB, and
+LSB is replaced by status byte (so ID 5A80h becomes 8000h=Multitap/okay, or
+xxFFh=bad). Halfwords 1,5,9,13 are NOT parsed (neither by the BIOS nor by the
+Multitap hardware), however, some info in the internet is hinting that Sony's
+libraries might be parsing these IDs too (so for example 5A41h would become
+4100h=DigitalPad/okay, or xxFFh=bad).
+
+Power Supply
+The Multitap is powered by the PSX controller port. Unknown if there are any
+power supply restrictions (up to eight controllers and eight cards may scratch
+some limits, especially when doing things like activating rumble on all
+joypads). However, the Multitap hardware itself doesn't do much on supply
+restrictions (+3.5V is passed through something; maybe some fuse, loop, or 1
+ohm resistor or so) (and +7.5V is passed without any restrictions).
+
+See also
+--> Pinouts - Component List and Chipset Pin-Outs for Multitap, SCPH-1070
+
+Controllers - Communication Sequence
+------------------------------------
+
+Controller Communication Sequence
+ Send Reply Comment
+ 01h Hi-Z Controller Access (unlike 81h=Memory Card access), dummy response
+ 42h idlo Receive ID bit0..7 (variable) and Send Read Command (ASCII "B")
+ TAP idhi Receive ID bit8..15 (usually/always 5Ah)
+ MOT swlo Receive Digital Switches bit0..7
+ MOT swhi Receive Digital Switches bit8..15
+ --- transfer stops here for digital pad (or analog pad in digital mode) ---
+ 00h adc0 Receive Analog Input 0 (if any) (eg. analog joypad or mouse)
+ 00h adc1 Receive Analog Input 1 (if any) (eg. analog joypad or mouse)
+ --- transfer stops here for analog mouse ----------------------------------
+ 00h adc2 Receive Analog Input 2 (if any) (eg. analog joypad)
+ 00h adc3 Receive Analog Input 3 (if any) (eg. analog joypad)
+ --- transfer stops here for analog pad (in analog mode) -------------------
+ --- transfer stops here for nonstandard devices (steering/twist/paddle) ---
+The TAP byte should be usually zero, unless one wants to activate Multitap
+(multi-player mode), for details, see
+--> Controller and Memory Card Multitap Adaptor
+The two MOT bytes are meant to control the rumble motors (for normal non-rumble
+controllers, that bytes should be 00h), however, the MOT bytes have no effect
+unless rumble is enabled via config commands, for details, see
+--> Controllers - Configuration Commands
+--> Controllers - Vibration/Rumble Control
+
+Controller ID (Halfword Number 0)
+ 0-3 Number of following halfwords (01h..0Fh=1..15, or 00h=16 halfwords)
+ 4-7 Controller Type (or currently selected Controller Mode)
+ 8-15 Fixed (5Ah)
+Known 16bit ID values are:
+ xx00h=N/A (initial buffer value from InitPad BIOS function)
+ 5A12h=Mouse (two button mouse)
+ 5A23h=NegCon (steering twist/wheel/paddle)
+ 5A31h=Konami Lightgun (IRQ10-type)
+ 5A41h=Digital Pad (or analog pad/stick in digital mode; LED=Off)
+ 5A53h=Analog Stick (or analog pad in "flight mode"; LED=Green)
+ 5A63h=Namco Lightgun (Cinch-type)
+ 5A73h=Analog Pad (in normal analog mode; LED=Red)
+ 5A7xh=Dualshock2 (with variable number of inputs enabled)
+ 5A79h=Dualshock2 (with all analog/digital inputs enabled)
+ 5A80h=Multitap (multiplayer adaptor) (when activated)
+ 5A96h=Keyboard (rare lightspan keyboard)
+ 5AE3h=Jogcon (steering dial)
+ 5AE8h=Keyboard/Sticks (rare homebrew keyboard/segasticks adaptor)
+ 5AF3h=Config Mode (when in config mode; see rumble command 43h)
+ FFFFh=High-Z (no controller connected, pins floating High-Z)
+
+Controllers - Standard Digital/Analog Controllers
+-------------------------------------------------
+ ___ ___ ___ ___
+ __/_L_\__ Analog Pad __/_R_\__ __/_L_\__ Digital Pad __/_R_\__
+ / _ \--------------/ \ / _ \--------------/ \
+ | _| |_ | | /\ | | _| |_ | | /\ |
+ | |_ X _| |SEL STA| [] () | | |_ X _| | | [] () |
+ | |_| ___ ANALOG ___ >< | | |_| | SEL STA | >< |
+ |\______ / L \ LED / R \ ______/| |\_________/--------------\_________/|
+ | | Joy |--------| Joy | | | | | |
+ | / \___/ \___/ \ | | / \ |
+ \____/ \____/ \____/ \____/
+
+Standard Controllers
+ __Halfword 0 (Controller Info)_______________________________________________
+ 0-15 Controller Info (5A41h=digital, 5A73h=analog/pad, 5A53h=analog/stick)
+ __Halfword 1 (Digital Switches)______________________________________________
+ 0 Select Button (0=Pressed, 1=Released)
+ 1 L3/Joy-button (0=Pressed, 1=Released/None/Disabled) ;analog mode only
+ 2 R3/Joy-button (0=Pressed, 1=Released/None/Disabled) ;analog mode only
+ 3 Start Button (0=Pressed, 1=Released)
+ 4 Joypad Up (0=Pressed, 1=Released)
+ 5 Joypad Right (0=Pressed, 1=Released)
+ 6 Joypad Down (0=Pressed, 1=Released)
+ 7 Joypad Left (0=Pressed, 1=Released)
+ 8 L2 Button (0=Pressed, 1=Released) (Lower-left shoulder)
+ 9 R2 Button (0=Pressed, 1=Released) (Lower-right shoulder)
+ 10 L1 Button (0=Pressed, 1=Released) (Upper-left shoulder)
+ 11 R1 Button (0=Pressed, 1=Released) (Upper-right shoulder)
+ 12 /\ Button (0=Pressed, 1=Released) (Triangle, upper button)
+ 13 () Button (0=Pressed, 1=Released) (Circle, right button)
+ 14 >< Button (0=Pressed, 1=Released) (Cross, lower button)
+ 15 [] Button (0=Pressed, 1=Released) (Square, left button)
+ __Halfword 2 (Right joystick) (analog pad/stick in analog mode only)_________
+ 0-7 adc0 RightJoyX (00h=Left, 80h=Center, FFh=Right)
+ 8-15 adc1 RightJoyY (00h=Up, 80h=Center, FFh=Down)
+ __Halfword 3 (Left joystick) (analog pad/stick in analog mode only)__________
+ 0-7 adc2 LeftJoyX (00h=Left, 80h=Center, FFh=Right)
+ 8-15 adc3 LeftJoyY (00h=Up, 80h=Center, FFh=Down)
+ __Further Halfword(s) (Dualshock2 only, and only if enabled)_________________
+ 0-7 .. Analog Button (if enabled) (00h=Released, FFh=Max Pressure)
+ 8-15 .. Analog Button (if enabled) (00h=Released, FFh=Max Pressure)
+ .. .. ..
+
+Analog Mode Note
+On power-up, the controllers are in digital mode (with analog inputs disabled).
+Analog mode can be (de-)activated manually by pushing the Analog button.
+Alternately, analog mode can be (de-)activated by software via rumble
+configuration commands (though that's supported only on newer pads; those with
+two rumble motors).
+The analog sticks are mechanically restricted to a "circular field of motion"
+(most joypads can reach "min/max" values only in "straight" horizontal or
+vertical directions, but not in "diagonal" directions).
+
+Analog Joypad Range
+ ...''''''''''...
+ ____ .''________________''._____ ___ 00h
+ | .'' ''. |
+ |.' '.| ___ 10h
+ .' '.
+ :| |:
+ : | | : ___ 60h
+ .' | .''''''. | '.
+ : | .' '. | :
+ : | : : | : ___ 80h
+ : | : : | :
+ : | '. .' | :
+ '. | '......' | .' ___ A0h
+ : | | :
+ :| |:
+ '. .' ___ F0h
+ |'. .'|
+ |__'..______________________..'__| ___ FFh
+ . '.. ..' .
+ 00h '''..........''' FFh
+
+ Big Circle --> Mechanically possible field of motion
+ Square Area --> Digitally visible 8bit field of motion
+ Small Circle --> Resting position when releasing the joystick
+Example min/center/max values for three different pads:
+ SCPH-1150 Min=(00,00), Mid: (72..90,79..AC), Max=(FF,FF) at 25'C
+ SCPH-1200 Min=(0E,0E), Mid: (6C..8A,75..79), Max=(ED,ED) at 16'C
+ SCPH-110 Min=(11,11), Mid: (8A..9F,70..96), Max=(FD,FD) at 16'C
+Values may vary for other pads and/or different temperatures.
+
+Dual Analog Pad in LED=Green Mode
+Basically same as normal analog LED=Red mode, with following differences:
+ ID is 5A53h (identifying itself as analog stick) (rather than analog pad)
+ Left/right joy-buttons disabled (as for real analog stick, bits are always 1)
+ Some buttons are re-arranged: bit9=L1 bit10=[] bit11=/\ bit12=R1 bit15=R2
+Concerning the button names, the real analog-stick does NOT have re-arranged
+buttons (eg. it's L1 button is in bit10), however, concerning the button
+locations, the analog stick's buttons are arranged completely differently as on
+analog pads (so it might be rather uncomfortable to play analog stick games on
+analog pads in LED=Red mode; the LED=Green mode is intended to solve that
+problem).
+Might be useful for a few analog-stick games like MechWarrior 2, Ace Combat 2,
+Descent Maximum, and Colony Wars. In most other cases the feature is rather
+confusing (that's probably why the LED=Green mode wasn't implemented on the
+Dual Shock).
+
+See also
+--> Pinouts - Component List and Chipset Pin-Outs for Digital Joypad, SCPH-1080
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1150
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1200
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-110
+--> Pinouts - Component List and Chipset Pin-Outs for Dualshock2, SCPH-10010
+
+Controllers - Mouse
+-------------------
+
+Sony Mouse Controller
+ __Halfword 0 (Controller Info)________________
+ 0-15 Controller Info (5A12h=Mouse)
+ __Halfword 1 (Mouse Buttons)__________________
+ 0-7 Not used (All bits always 1)
+ 8-9 Unknown (Seems to be always 0) (maybe SNES-style sensitivity?)
+ 10 Right Button (0=Pressed, 1=Released)
+ 11 Left Button (0=Pressed, 1=Released)
+ 12-15 Not used (All bits always 1)
+ __Halfword 2 (Mouse Motion Sensors)___________
+ 0-7 Horizontal Motion (-80h..+7Fh = Left..Right) (00h=No motion)
+ 8-15 Vertical Motion (-80h..+7Fh = Up..Down) (00h=No motion)
+
+Sony Mouse Hardware Bug on Power-On
+On Power-on (or when newly connecting it), the Sony mouse does draw /ACK to LOW
+on power-on, and does then hold /ACK stuck in the LOW position.
+For reference: Normal controllers and memory cards set /ACK=LOW only for around
+100 clk cycles, and only after having received a byte from the console.
+The /ACK pin is shared for both controllers and both memory cards, so the stuck
+/ACK is also "blocking" all other connected controllers/cards. To release the
+stuck /ACK signal: Send a command (at least one 01h byte) to both controller
+slots.
+
+Sony Mouse Compatible Games
+ 3D Lemmings
+ Alien Resurrection
+ Area 51
+ Ark of Time
+ Atari Anniversary Edition
+ Atlantis: The Lost Tales
+ Breakout: Off the Wall Fun
+ Broken Sword: The Shadow of the Templars
+ Broken Sword II: The Smoking Mirror
+ Clock Tower: The First Fear
+ Clock Tower II: The Struggle Within
+ Command & Conquer: Red Alert
+ Command & Conquer: Red Alert - Retaliation
+ Constructor (Europe)
+ Die Hard Trilogy
+ Die Hard Trilogy 2: Viva Las Vegas
+ Discworld
+ Discworld II: Missing Presumed...!?
+ Discworld Noir
+ Dune 2000
+ Final Doom
+ Galaxian 3
+ Ghoul Panic
+ Klaymen Klaymen: Neverhood no Nazon (Japan)
+ Lemmings and Oh No! More Lemmings
+ Monopoly
+ Music 2000
+ Myst
+ Neorude (Japan)
+ Perfect Assassin
+ Policenauts (Japan)
+ Puchi Carat
+ Quake II
+ Railroad Tycoon II
+ Rescue Shot
+ Risk
+ Riven: The Sequel to Myst
+ RPG Maker
+ Sentinel Returns
+ SimCity 2000
+ Syndicate Wars
+ Tempest 2000 (Tempest X3)
+ Theme Aquarium (Japan)
+ Transport Tycoon
+ Warhammer: Dark Omen
+ Warzone 2100
+ X-COM: Enemy Unknown
+ X-COM: Terror from the Deep
+ Z
+Note: There are probably many more mouse compatible games.
+Plus: Dracula - The Resurrection
+
+Sony Mouse Component List
+PCB "TD-T41V/\, MITSUMI"
+Component Side:
+ 1x 3pin 4.00MHz "[M]4000A, 85 2"
+ 2x 2pin button (left/right)
+ 1x 8pin connector (to cable with shield and 7 wires)
+ 1x 3pin "811, T994I"
+ 2x 3pin photo transistor (black) ;\or so, no idea which one is
+ 2x 2pin photo diode (transparent) ;/sender and which is sensor
+ 1x 2pin electrolyt capacitor 16V, 10uF
+Solder/SMD Side:
+ 1x 32pin "(M), SC442116, FB G22K, JSAA815B"
+ 1x 14pin "BA10339F, 817 L67" (Quad Comparator)
+ 2x 3pin "LC" (amplifier for photo diodes)
+ 1x 3pin "24-" (looks like a dual-diode or so)
+ plus many SMD resistors/capacitors
+Cable:
+ PSX.Controller.Pin1 JOYDAT ---- brown -- Mouse.Pin4
+ PSX.Controller.Pin2 JOYCMD ---- red -- Mouse.Pin3
+ PSX.Controller.Pin3 +7.5V ---- N/A
+ PSX.Controller.Pin4 GND ---- orange -- Mouse.Pin7 GND (G)
+ PSX.Controller.Pin5 +3.5V ---- yellow -- Mouse.Pin1
+ PSX.Controller.Pin6 /JOYn ---- green -- Mouse.Pin5
+ PSX.Controller.Pin7 JOYCLK ---- blue -- Mouse.Pin2
+ PSX.Controller.Pin8 /IRQ10 ---- N/A
+ PSX.Controller.Pin9 /ACK ---- purple -- Mouse.Pin6
+ PSX.Controller.Shield --------- shield -- Mouse.Pin8 GND (SHIELD)
+
+PS/2 and USB Mouse Adaptors
+Some keyboard adaptors are also including a mouse adpator feature (either by
+simulating normal Sony Mouse controller data, or via more uncommon ways like
+using the PSX expansion port).
+--> Controllers - Keyboards
+
+RS232 Mice
+Below is some info on RS232 serial mice. That info isn't directly PSX related
+as the PSX normally doesn't support those mice.
+With some efforts, one can upgrade the PSX SIO port to support RS232 voltages,
+and with such a modded console one could use RS232 mice (in case one wants to
+do that).
+The nocash PSX bios can map a RS232 mouse to a spare controller slot (thereby
+simulating a Sony mouse), that trick may work with various PSX games.
+
+Standard Serial Mouse
+A serial mouse should be read at 1200 bauds, 7 data bits, no parity, 1 stop bit
+(7N1) with DTR and RTS on. For best compatibility, the mouse should output 2
+stop bits (so it could be alternately also read as 7N2 or 8N1). When the mouse
+gets moved, or when a button gets pressed/released, the mouse sends 3 or 4
+characters:
+ __First Character____________________
+ 6 First Character Flag (1)
+ 5 Left Button (1=Pressed)
+ 4 Right Button (1=Pressed)
+ 2-3 Upper 2bit of Vertical Motion
+ 0-1 Upper 2bit of Horizontal Motion
+ __Second Character___________________
+ 6 Non-first Character Flag (0)
+ 5-0 Lower 6bit of Horizontal Motion
+ __Third Character____________________
+ 6 Non-first Character Flag (0)
+ 5-0 Lower 6bit of Vertical Motion
+ __Fourth Character (if any)__________
+ 6 Non-first Character Flag (0)
+ 5 Middle Button (1=Pressed)
+ 4 Unused ???
+ 3-0 Wheel ???
+Additionally, the mouse outputs a detection character (when switching RTS (or
+DTR?) off and on:
+ "M" = Two-Button Mouse (aka "Microsoft" mouse)
+ "3" = Three-Button Mouse (aka "Logitech" mouse)
+ "Z" = Mouse-Wheel
+Normally, the detection response consist of a single character (usually "M"),
+though some mice have the "M" followed by 11 additional characters of garbage
+or version information (these extra characters have bit6=0, so after detection,
+one should ignore all characters until receiving the first data character with
+bit6=1).
+
+Mouse Systems Serial Mouse (rarely used)
+Accessed at 1200 bauds, just like standard serial mouse, but with 8N1 instead
+7N1, and with different data bytes.
+ __First Byte_________________________
+ 7-3 First Byte Code (10000b)
+ 2 Left? Button (0=Pressed)
+ 1 Middle? Button (0=Pressed)
+ 0 Right? Button (0=Pressed)
+ __Second Byte________________________
+ 7-0 Horizontal Motion (X1)
+ __Third Byte_________________________
+ 7-0 Vertical Motion (Y1)
+ __Fourth Byte________________________
+ 7-0 Horizontal Motion (X2)
+ __Fifth Byte_________________________
+ 7-0 Vertical Motion (Y2)
+The strange duplicated 8bit motion values are usually simply added together,
+ie. X=X1+X2 and Y=Y1+Y2, producing 9bit motion values.
+
+Notes
+The Sony Mouse connects directly to the PSX controller port. Alternately serial
+RS232 mice can be connected to the SIO port (with voltage conversion adaptor)
+(most or all commercial games don't support SIO mice, nor does the original
+BIOS do so, however, the nocash BIOS maps SIO mice to unused controller slots,
+so they can be used even with commercial games; if the game uses BIOS functions
+to read controller data).
+Serial Mice (and maybe also the Sony mouse) do return raw mickeys, so effects
+like double speed threshold must (should) be implemented by software. Mice are
+rather rarely used by PSX games. The game "Perfect Assassin" includes
+ultra-crude mouse support, apparently without threshold, and without properly
+matching the cursor range to the screen resolution.
+
+Controllers - Racing Controllers
+--------------------------------
+
+neGcon Racing Controller (Twist) (NPC-101/SLPH-00001/SLEH-0003)
+ __Halfword 0 (Controller Info)_______________________________________________
+ 0-15 Controller Info (5A23h=neGcon)
+ __Halfword 1 (Digital Switches)______________________________________________
+ 0-2 Not used (always 1) (would be Select, L3, R3 on other pads)
+ 3 Start Button (0=Pressed, 1=Released)
+ 4 Joypad Up (0=Pressed, 1=Released)
+ 5 Joypad Right (0=Pressed, 1=Released)
+ 6 Joypad Down (0=Pressed, 1=Released)
+ 7 Joypad Left (0=Pressed, 1=Released)
+ 8-10 Not used (always 1) (would be L2, R2, L1 on other pads)
+ 11 R Button (0=Pressed, 1=Released) (would be R1 on other pads)
+ 12 B Button (0=Pressed, 1=Released) (would be /\ on other pads)
+ 13 A Button (0=Pressed, 1=Released) (would be () on other pads)
+ 14-15 Not used (always 1) (would be ><, [] on other pads)
+ __Halfword 2 (Right joystick) (analog pad/stick in analog mode only)_________
+ 0-7 Steering Axis (00h=Left, 80h=Center, FFh=Right) (or vice-versa?)
+ 8-15 Analog I button (00h=Out ... FFh=In) (Out=released, in=pressed?)
+ __Halfword 3 (Left joystick) (analog pad/stick in analog mode only)__________
+ 0-7 Analog II button (00h=Out ... FFh=In) (Out=released, in=pressed?)
+ 8-15 Analog L button (00h=Out ... FFh=In) (Out=released, in=pressed?)
+The Twist controller works like a paddle or steering wheel, but doesn't have a
+wheel or knob, instead, it can be twisted: To move into one direction (=maybe
+right?), turn its right end away from you (or its left end towards you). For
+the opposite direction (=maybe left?), do it vice-versa.
+ _____ _ _ _____ ____
+ |__L__\_______/ || \_______/__R__| / \
+ / _ namco || neGcon \ / \
+ | _| |_ || B | | |
+ | |_ X _| ....||.... II A | .... Rotation Axis ... | ... \|/
+ | |_| || I | |
+ | START || | \
+ | ________ || ________ | \__\
+ | / \_||_/ \ | /
+ \____/ \____/
+
+Namco Volume Controller (a paddle with two buttons) (SLPH-00015)
+This is a cut-down variant of the neGcon, just a featureless small box. It does
+have the same ID value as neGcon (ID=5A23h), but, it excludes most digital, and
+all analog buttons.
+ _______
+ | namco | Halfword 1 (digital buttons):
+ | | Bit3 Button A (0=Pressed) (aka neGcon Start button)
+ | A B | Bit13 Button B (0=Pressed) (aka neGcon A button aka () button)
+ | | Other bits (not used, always 1)
+ | _ | Halfword 2 and 3 (analog inputs):
+ | (_) | Steering Axis (00h..FFh) (as for neGcon)
+ |_______| Analog I,II,L button values (not used, always 00h)
+
+SANKYO N.ASUKA aka Nasca Pachinco Handle (SLPH-00007)
+Another cut-down variant of the neGcon (with ID=5A23h, too). But, this one
+seems to have only one button. Unlike Namco's volume controller it doesn't look
+featureless. It looks pretty much as shown in the ascii-arts image below. Seems
+to be supported by several irem titles. No idea what exactly it is used for,
+it's probably not a sewing machine controller, nor an electronic amboss.
+ ____ ____ Halfword 1 (digital buttons):
+ | / _ \ Bit12 Button (0=Pressed) (aka neGcon B button aka /\ button)
+ |_ / (_) ) Other bits (not used, always 1)
+ |_|___ /\ Halfword 2 and 3 (analog inputs):
+ ____| |_ Steering Axis (00h..FFh) (as for neGcon)
+ |__________| Analog I,II,L button values (not used, always 00h)
+
+Mad Catz Steering Wheel (SLEH-0006)
+A neGcon compatible controller. The Twist-feature has been replaced by a
+steering wheel (can be turned by 270 degrees), and the analog I and II buttons
+by foot pedals. The analog L button has been replaced by a digital button (ie.
+in neGcon mode, the last byte of the controller data can be only either 00h or
+FFh). When not using the pedals, the I/II buttons on the wheel can be used
+(like L button, they aren't analog though).
+ __________________________
+ / ____________________ \ Stick
+ / / \ \ ___ Brakes Gas
+ / ( ) \ ( ) II I
+ / I \ / A \ \ / ___ ___
+ / /\ II \____________MODE__/ B /\ \ | | | | |
+ | | \ L _ R / | | | |!!!|_|!!!|___
+ | | ) _| |_ MadCatz ( | |_|_ /|!!!| |!!!| /
+ | | | |_ X _| | | | | | / |___| |___| /
+ | | | |_| | | | / / =========== /
+ | | \ SEL STA / | | / / =========== /
+ \ \__/ ______________________ \__/ / / /_____________/
+ \____/ \____/_/
+ |___________________________|
+
+Unlike the neGon, the controller has Select, >< and [] buttons, and a second
+set of L/R buttons (at the rear-side of the wheel) (no idea if L1/R1 or L2/R2
+are at front?). Aside from the neGcon mode, the controller can be also switched
+to Digital mode (see below for button chart).
+
+MadCatz Dual Force Racing Wheel
+Same as above, but with a new Analog mode (additionally to Digital and neGcon
+modes). The new mode is for racing games that support only Analog Joypads
+(instead of neGcon). Additionally it supports vibration feedback.
+
+MadCatz MC2 Vibration compatible Racing Wheel and Pedals
+Same as above, but with a redesigned wheel with rearranged buttons, the digital
+pad moved to the center of the wheel, the L/R buttons at the rear-side of the
+wheel have been replaced by 2-way butterfly buttons ("pull towards user" acts
+as normal, the new "push away from user" function acts as L3/R3).
+ ____________________
+ / ________________ \ ___ Stick Brakes Gas
+ / / MC2 \ \ ( ) ___ ___
+ / /__________________\ \ \ / | | | |
+ | A () _|_ I >< | | |!!!|_|!!!|___
+ | B /\ _ | _ II [] | | /|!!!| |!!!| /
+ ___| L2 / \ STA / \ R2 |_|_ / |___| |___| /
+ / \ / | SEL | \ / \ / =========== /
+ / ____\ |___| |___| /____ \ / =========== /
+ /__/ \____________________/ \__\ /_____________/
+
+MadCatz Button Chart
+ Mode Buttons...................... Gas Brake Stick Wheel
+ Digital >< [] () /\ L1 R1 L2 R2 L1 R1 >< () L1/R1 lt/rt
+ Analog >< [] () /\ L1 R1 L2 R2 L3 R3 UP DN L1/R1 LT/RT
+ Negcon I II A B L R L R L R I II up/dn Twist
+Whereas, lt/rt/up/dn=Digital Pad, UP/DN=Left Analog Pad Up/Down, LT/RT=Right
+Analog Pad Left/Right. Analog mode is supported only by the Dual Force and MC2
+versions, L3/R3 only by the MC2 version.
+
+Namco Jogcon (NPC-105/SLEH-0020/SLPH-00126/SLUH-00059)
+ __Halfword 0 (Controller Info)___________________
+ 0-15 Controller Info (5AE3h=Jogcon in Jogcon mode) (ie. not Digital mode)
+ halfword1: buttons: same as digital pad
+ halfword2:
+ 0 unknown (uh, this isn't LSB of rotation?)
+ 1-15 dial rotation (signed offset since last read?) (or absolute position?)
+ halfword3:
+ 0 flag: dial was turned left (0=no, 1=yes)
+ 1 flag: dial was turned right (0=no, 1=yes)
+ 2-15 unknown
+Rotations of the dial are recognized by an optical sensor (so, unlike
+potentiometers, the dial can be freely rotated; by more than 360 degrees). The
+dial is also connected to a small motor, giving it a real force-feedback effect
+(unlike all other PSX controllers which merely have vibration feedback).
+Although that's great, the mechanics are reportedly rather cheap and using the
+controller doesn't feel too comfortable. The Jogcon is used only by Ridge Racer
+4 for PS1 (and Ridge Racer 5 for PS2), and Breakout - Off the Wall Fun.
+The Mode button probably allows to switch between Jogcon mode and Digital Pad
+mode (similar to the Analog button on other pads), not sure if the mode can be
+also changed by software via configuration commands...? Unknown how the motor
+is controlled; probably somewhat similar to vibration motors, ie. by the M1
+and/or M2 bytes, but there must be also a way to select clockwise and
+anticlockwise direction)...? The controller does reportedly support config
+command 4Dh (same as analog rumble).
+ ___ ________ ___
+ __/_L_\__ / \ __/_R_\__
+ / _ \ / LED MODE \-/ \
+ | _| |_ | SEL STA | /\ |
+ | |_ X _| | ________ | [] () |
+ | |_| | / \ | >< |
+ |\_________/\/ \/\__ ______/|
+ | | | JOGCON | | |
+ | | | DIAL | | |
+ | | \ / | |
+ | | \________/ | |
+ | | | |
+ | | | |
+ \_____/ \_____/
+
+Controllers - Lightguns
+-----------------------
+
+There are two different types of PSX lightguns (which are incompatible with
+each other).
+
+Namco Lightgun (GunCon)
+Namco's Cinch-based lightguns are extracting Vsync/Hsync timings from the video
+signal (via a cinch adaptor) (so they are working completely independed of
+software timings).
+--> Controllers - Lightguns - Namco (GunCon)
+
+Konami Lightgun (IRQ10)
+Konami's IRQ10-based lightguns are using the lightgun input on the controller
+slot (which requires IRQ10/timings being properly handled at software side).
+--> Controllers - Lightguns - Konami Justifier/Hyperblaster (IRQ10)
+The IRQ10-method is reportedly less accurate (although that may be just due to
+bugs at software side).
+
+Third-Party Lightguns
+There are also a lot of unlicensed lightguns which are either IRQ10-based, or
+Cinch-based, or do support both.
+For example, the Blaze Scorpion supports both IRQ10 and Cinch, and it does
+additionally have a rumble/vibration function; though unknown how that rumble
+feature is accessed, and which games are supporting it).
+
+Lightgun Games
+--> Controllers - Lightguns - PSX Lightgun Games
+
+Compatibilty Notes (IRQ10 vs Cinch, PAL vs NTSC, Calibration)
+Some lightguns are reportedly working only with PAL or only with NTSC games
+(unknown which guns, and unknown what is causing problems; the IRQ10 method
+should be quite hardware independed, the GunCon variant, too, although
+theoretically, some GunCon guns might have problems to extract Vsync/Hsync from
+either PAL or NTSC composite signals).
+Lightguns from different manufacturers are reportedly returning slightly
+different values, so it would be recommended to include a calibration function
+in the game, using at least one calibration point (that would also resolve
+different X/Y offsets caused by modifying GP1 display control registers).
+Lightguns are needing to sense light from the cathode ray beam; as such they
+won't work on regions of the screen that contain too dark/black graphics.
+
+Controllers - Lightguns - Namco (GunCon)
+----------------------------------------
+
+GunCon Cinch-based Lightguns (Namco)
+ __Halfword 0 (Controller Info)___________________
+ 0-15 Controller Info (5A63h=Namco Lightgun; GunCon/Cinch Type)
+ __Halfword 1 (Buttons)___________________________
+ 0-2 Not used (All bits always 1)
+ 3 Button A (Left Side) (0=Pressed, 1=Released) ;aka Joypad Start
+ 4-12 Not used (All bits always 1)
+ 13 Trigger Button (0=Pressed, 1=Released) ;aka Joypad O-Button
+ 14 Button B (Right Side) (0=Pressed, 1=Released) ;aka Joypad X-Button
+ 15 Not used (All bits always 1)
+ __Halfword 2 (X)_________________________________
+ 0-15 8MHz clks since HSYNC (01h=Error, or 04Dh..1CDh)
+ __Halfword 3 (Y)_________________________________
+ 0-15 Scanlines since VSYNC (05h/0Ah=Error, PAL=20h..127h, NTSC=19h..F8h)
+Caution: The gun should be read only shortly after begin of VBLANK.
+
+Error/Busy Codes
+Coordinates X=0001h, Y=0005h indicates "unexpected light":
+ ERROR: Sensed light during VSYNC (eg. from a Bulb or Sunlight).
+Coordinates X=0001h, Y=000Ah indicates "no light", this can mean either:
+ ERROR: no light sensed at all (not aimed at screen, or screen too dark).
+ BUSY: no light sensed yet (when trying to read gun during rendering).
+To avoid the BUSY error, one should read the gun shortly after begin of VBLANK
+(ie. AFTER rendering, but still BEFORE vsync). Doing that isn't as simple as
+one might think:
+On a NTSC console, time between VBLANK and VSYNC is around 30000 cpu clks,
+reading the lightgun (or analog joypads) takes around 15000 cpu clks. So,
+reading two controllers within that timeframe may be problematic (and reading
+up to eight controllers via multitaps would be absolutely impossible). As a
+workaround, one may arrange the read-order to read lightguns at VBLANK (and
+joypads at later time). If more than one lightgun is connected, then one may
+need to restrict reading to only one (or maybe: max two) guns per frame.
+
+Minimum Brightness
+Below are some average minimum brightness values, the gun may be unable to
+return position data near/below that limits (especially coordinates close to
+left screen border are most fragile). The exact limits may vary from gun to
+gun, and will also depend on the TV Set's brightness setting.
+ 666666h Minimum Gray
+ 770000h Minimum Blue
+ 007700h Minimum Green
+ 000099h Minimum Red
+The gun does also work with mixed colors (eg. white bold text on black
+background works without errors, but the returned coordinates are a bit "jumpy"
+in that case; returning the position of the closest white pixels).
+BUG: On a plain RED screen, aiming at Y>=00F0h, the gun is randomly returning
+either Y, or Y-80h (that error occurs in about every 2nd frame, ie. at 50%
+chance). It's strange... no idea what is causing that effect.
+
+Coordinates
+The coordinates are updated in all frames (as opposed to some lightguns which
+do update them only when pulling the trigger).
+The absolute min/max coordinates may vary from TV set to TV set (some may show
+a few more pixels than others). The relation of the gun's Screen Coodinates to
+VRAM Coordinates does (obviously) depend on where the VRAM is located on the
+screen; ie. on the game's GP1(06h) and GP1(07h) settings.
+Vertical coordinates are counted in scanlines (ie. equal to pixels). Horizontal
+coordinates are counted in 8MHz units (which would equal a resolution of 385
+pixels; which can be, for example, converted to 320 pixel resolution as
+X=X*320/385).
+
+Misinformation (from bugged homebrew source code)
+ __Halfword 2 (X)_________________________________
+ 0-7 X-Coordinate (actual: see X-Offset) ;\with unspecified
+ 8-15 X-Offset (00h: X=X-80, Nonzero: X=X-80+220) ;/dotclock?
+ __Halfword 3 (Y)_________________________________
+ 0-7 Y-Coordinate (actual: Y=Y-25) (but then, max is only 230, not 263 ?)
+ 8-15 Pad ID (uh, what id?) (reportedly too dark/bright error flag?)
+
+Namco Lightgun Drawing
+ _-_______________________--_
+ -----> | namco \\\\ \ Namco G-Con 45 (light gray) (cinch)
+ sensor |............ .. .....\\\\...|_
+ |_ : :.. _____ _\
+ | O :__../ )))| (
+ \__________/ |_\____/| \
+ : : | |
+ : : | | NPC-103
+ A-Button (Left) Trigger | | SLPH-00034/SLEH-0007/SLUH-00035
+ B-Button (Right) |______|
+
+See also
+--> Pinouts - Component List and Chipset Pin-Outs for Namco Lightgun, NPC-103
+
+Controllers - Lightguns - Konami Justifier/Hyperblaster (IRQ10)
+---------------------------------------------------------------
+
+Overall IRQ10-Based Lightgun Access
+ Send 01h 42h 00h x0h 00h
+ Reply HiZ 31h 5Ah buttons
+The purpose of the "x0h" byte is probably to enable IRQ10 (00h=off, 10h=on),
+this would allow to access more than one lightgun (with only one per frame
+having the IRQ enabled).
+
+Standard IRQ10-based Lightguns (Konami)
+The Controller Data simply consists of the ID and buttons states:
+ __Halfword 0 (Controller Info)___________________
+ 0-15 Controller Info (5A31h=Konami Lightgun; Timer/IRQ10 type)
+ __Halfword 1 (Buttons)
+ 0-2 Not used (All bits always 1)
+ 3 Start Button (Left Side) (0=Pressed, 1=Released) ;aka Joypad Start
+ 4-13 Not used (All bits always 1)
+ 14 Back Button (Rear End) (0=Pressed, 1=Released) ;aka Joypad X-Button
+ 15 Trigger Button (0=Pressed, 1=Released) ;aka Joypad []-Button
+The coordinates aren't part of the controller data, instead they must be read
+from Timer 0 and 1 upon receiving IRQ10 (see IRQ10 Notes below).
+
+Konami Lightgun Drawing
+ __ ______ _
+ _|__\_______________/ ___ \ \ Konami Justifier/Hyperblaster (light green)
+ | _______________ __ / \ \ \
+ |__| _ _ _ _ |==| O| \O\ .... Back Button (Rear End)
+ |__:_:_:_:_:__ |___\__ / ( (
+ |_| ) \ : \ \
+ Trigger ...... \___/| :...|.|.... Start Button (Left Side)
+ | | |
+ | | | SLPH-00013/SLPH-00014/SLEH-0005/SLUH-00017
+ / _|_|
+ \___--
+
+Konami IRQ10 Notes
+The PSX does have a lightgun input (Pin 8 of the controller), but, Sony did
+apparently "forget" to latch the current cathode ray beam coordinates by
+hardware when sensing the lightgun signal (quite strange, since that'd be a
+simple, inexpensive, and very obvious feature for a gaming console).
+Instead, the lightgun signal triggers IRQ10, and the interrupt handler is
+intended to "latch" the coordinates by software (by reading Timer 0 and 1
+values, which must configured to be synchronized with the GPU).
+That method requires IRQ handling to be properly implemented in software
+(basically, IRQs should not be disabled for longer periods, and DMA transfers
+should not block the bus for longer periods). In practice, most programmers
+probably don't realize how to do that, to the worst, Sony seems to have
+delivered a slightly bugged library (libgun) to developers.
+For details on Timers, see:
+--> Timers
+In some consoles, IRQ10 seems to be routed through a Secondary IRQ Controller,
+see:
+--> EXP2 DTL-H2000 I/O Ports
+
+IRQ10 Priority
+For processing IRQ10 as soon as possible, it should be assigned higher priority
+than all other IRQs (ie. when using the SysEnqIntRP BIOS function, it should be
+the first/newest element in priority chain 0). The libgun stuff assigns an even
+higher priority by patching the BIOS exception handler, causing IRQ10 to be
+processed shortly before processing the priority chains (the resulting IRQ
+priority isn't actually higher as when using 1st element of chain 0; the main
+difference is that it skips some time consuming code which pushes registers
+R4..R30). For details on that patch, see:
+--> BIOS Patches
+Even if IRQ10 has highest priority, execution of (older) other IRQs may cause a
+new IRQ10 to be executed delayed (because IRQs are disabled during IRQ
+handling), to avoid that problem: Best don't enable any other IRQs except IRQ0
+and IRQ10, or, if you need other IRQs, best have them enabled only during
+Vblank (there are no scanlines drawn during vblank, so IRQ10 should never
+trigger during that period). DMAs might also slow down IRQ execution, so best
+use them only during Vblank, too.
+
+IRQ10 Timer Reading
+To read the current timer values the IRQ10 handler would be required to be
+called <immediately> after receiving the IRQ10 signal, which is more or less
+impossible; if the main program is trying to read a mul/div/gte result while
+the mul/div/gte operation is still busy may stop the CPU for some dozens of
+clock cycles, and active DMA transfers or cache hits and misses in the IRQ
+handler may cause different timings, moreover, timings may become completely
+different if IRQs are disabled (eg. while another IRQ is processed).
+However, IRQ10 does also get triggered in the next some scanlines, so the first
+IRQ10 is used only as a notification that the CPU should watch out for further
+IRQ10's. Ie. the IRQ10 handler should disable all DMAs, acknowledge IRQ10, and
+then enter a waitloop that waits for the IRQ10 bit in I_STAT to become set
+again (or abort if a timeout occurs) and then read the timers, reportedly like
+so:
+ IF NTSC then X=(Timer0-140)*0.198166, Y=Timer1
+ IF PAL then X=(Timer0-140)*0.196358, Y=Timer1
+No idea why PAL/NTSC should use different factors, that factors are looking
+quite silly/bugged, theoretically, the pixel-to-clock ratio should be the
+exactly same for PAL and NTSC...?
+Mind that reading Timer values in Dotclock/Hblank mode is unstable, for Timer1
+this can be fixed by the read-retry method, for Timer0 this could be done too,
+but one would need to subtract the retry-time to get a correct coordinate;
+alternately Timer0 can run at system clock (which doesn't require read-retry),
+but it must be then converted to video clock (mul 11, div 7), and then from
+video clock to dot clock (eg. div 8 for 320-pixel mode).
+Above can be repeated for the next some scanlines (allowing to take the medium
+values as result, and/or to eliminate faulty values which are much bigger or
+smaller than the other values). Once when you have collected enough values,
+disable IRQ10, so it won't trigger on further scanlines within the current
+frame.
+
+IRQ10 Bugs
+BUG: The "libgun" library doesn't acknowledge the old IRQ10 <immediately>
+before waiting for a new IRQ10, so the timer values after sensing the new IRQ10
+are somewhat random (especially for the first processed scanline) (the library
+allows to read further IRQ10's in further scanlines, which return more stable
+results).
+No idea how many times IRQ10 gets typically repeated? Sporting Clays allocates
+a buffer for up to 20 scanlines (which would cause pretty much of a slowdown
+since the CPU is just waiting during that period) (nethertheless, the game uses
+only the first timer values, ie. the bugged libgun-random values).
+
+Unknown if/how two-player games (with 2 lightguns) are working with the IRQ10
+method... if IRQ10 is generated ONLY after pressing the trigger button, then it
+may work, unless both players have Trigger pressed at the same time... and,
+maybe one can enable/disable the lightguns by whatever commmand being sent to
+the controller (presumably that "x0h" byte, see above), so that gun 1 generates
+IRQ10 only in each second frame, and gun 2 only in each other frame...?
+
+Controllers - Lightguns - PSX Lightgun Games
+--------------------------------------------
+
+PSX Lightgun Games
+Some games are working only with IRQ10 or only with Cinch, some games support
+both methods:
+ Area 51 (Mesa Logic/Midway) (IRQ10)
+ Crypt Killer (Konami) (IRQ10)
+ Die Hard Trilogy 1: (Probe Entertainment) (IRQ10)
+ Die Hard Trilogy 2: Viva Las Vegas (n-Space) (IRQ10/Cinch)
+ Elemental Gearbolt (Working Designs) (IRQ10/Cinch)
+ Extreme Ghostbusters: Ultimate Invasion (LSP) (Cinch)
+ Galaxian 3 (Cinch)
+ Ghoul Panic (Namco) (Cinch)
+ Gunfighter: The Legend of Jesse James (Rebellion) (Cinch)
+ Judge Dredd (Gremlin) (Cinch)
+ Lethal Enforcers 1-2 (Konami) (IRQ10)
+ Maximum Force (Midway) (IRQ10/Cinch)
+ Mighty Hits Special (Altron) (EU/JPN) (Cinch)
+ Moorhuhn series (Phenomedia) (Cinch)
+ Point Blank 1-3 (Namco) (Cinch)
+ Project Horned Owl (Sony) (IRQ10)
+ Rescue Shot (Namco) (Cinch)
+ Resident Evil: Gun Survivor (Capcom) (JPN/PAL versions) (Cinch)
+ Silent Hill (IRQ10) ("used for an easter egg")
+ Simple 1500 Series Vol.024 - The Gun Shooting (unknown type)
+ Simple 1500 Series Vol.063 - The Gun Shooting 2 (unknown type)
+ Snatcher (IRQ10)
+ Sporting Clays (Charles Doty) (homebrew with buggy source code) (IRQ10/Cinch)
+ Star Wars Rebel Assault II (IRQ10)
+ Time Crisis, and Time Crisis 2: Project Titan (Namco) (Cinch)
+Note: The RPG game Dragon Quest Monsters does also contain IRQ10 lightgun code
+(though unknown if/when/where the game does use that code).
+
+
+Controllers - Configuration Commands
+------------------------------------
+
+Some controllers can be switched from Normal Mode to Config Mode. The Config
+Mode was invented for activating the 2nd rumble motor in SCPH-1200 analog
+joypads. Additionally, the Config commands can switch between analog/digital
+inputs (without needing to manually press the Analog button), activate more
+analog inputs (on Dualshock2), and read some type/status bytes.
+
+Normal Mode
+ 42h "B" Read Buttons (and analog inputs when in analog mode)
+ 43h "C" Enter/Exit Configuration Mode (stay normal, or enter)
+Transfer length in Normal Mode is 5 bytes (Digital mode), or 9 bytes (Analog
+mode), or up to 21 bytes (Dualshock2).
+
+Configuration Mode
+ 40h "@" Unused, or Dualshock2: Get/Set ButtonAttr?
+ 41h "A" Unused, or Dualshock2: Get Reply Capabilities
+ 42h "B" Read Buttons AND analog inputs (even when in digital mode)
+ 43h "C" Enter/Exit Configuration Mode (stay config, or exit)
+ 44h "D" Set LED State (analog mode on/off)
+ 45h "E" Get LED State (and Type/constants)
+ 46h "F" Get Variable Response A (depending on incoming bit)
+ 47h "G" Get whatever values (response HiZ F3h 5Ah 00h 00h 02h 00h 01h 00h)
+ 48h "H" Unknown (response HiZ F3h 5Ah 00h 00h 00h 00h 01h 00h)
+ 49h "I" Unused
+ 4Ah "J" Unused
+ 4Bh "K" Unused
+ 4Ch "L" Get Variable Response B (depending on incoming bit)
+ 4Dh "M" Get/Set RumbleProtocol
+ 4Eh "N" Unused
+ 4Fh "O" Unused, or Dualshock2: Set ReplyProtocol
+Transfer length in Config Mode is always 9 bytes.
+
+ ____________________________ Normal Mode Commands ____________________________
+
+Normal Mode - Command 42h "B" - Read Buttons (and analog inputs when enabled)
+ Send 01h 42h 00h xx yy (00h 00h 00h 00h) (...)
+ Reply HiZ id 5Ah buttons ( analog-inputs ) (dualshock2 buttons...)
+The normal read command, see Standard Controller chapter for details on buttons
+and analog inputs. The xx/yy bytes have effect only if rumble is unlocked; use
+Command 43h to enter config mode, and Command 4Dh to unlock rumble. Command 4Dh
+has billions of combinations, among others allowing to unlock only one of the
+two motors, and to exchange the xx/yy bytes, however, with the default values,
+xx/yy are assigned like so:
+ yy.bit0-7 ---> Left/Large Motor M1 (analog slow/fast) (00h=stop, FFh=fastest)
+ xx.bit0 ---> Right/small Motor M2 (digital on/off) (0=off, 1=on)
+The Left/Large motor starts spinning at circa min=50h..60h, and, once when
+started keeps spinning downto circa min=38h. The exact motor start boundary
+depends on the current position of the weight (if it's at the "falling" side,
+then gravity helps starting), and also depends on external movements (eg. it
+helps if the user or the other rumble motor is shaking the controller), and may
+also vary from controller to controller, and may also depend on the room
+temperature, dirty or worn-out mechanics, etc.
+
+Normal Mode - Command 43h "C" - Enter/Exit Configuration Mode
+ Send 01h 43h 00h xx 00h (zero padded...) (...)
+ Reply HiZ id 5Ah buttons (analog inputs...) (dualshock2 buttons...)
+When issuing command 43h from inside normal mode, the response is same as for
+command 42h (button data) (and analog inputs when in analog mode) (but without
+M1 and M2 parameters). While in config mode, the ID bytes are always "F3h 5Ah"
+(instead of the normal analog/digital ID bytes).
+ xx=00h Stay in Normal mode
+ xx=01h Enter Configuration mode
+Caution: Additionally to activating configuration commands, entering config
+mode does also activate a Watchdog Timer which does reset the controller if
+there's been no communication for about 1 second or so. The watchdog timer
+remains active even when returning to normal mode via Exit Config command. The
+reset does disable and lock rumble motors, and switches the controller to
+Digital Mode (with LED=off, and analog inputs disabled). To prevent this, be
+sure to keep issuing joypad reads even when not needing user input (eg. while
+loading data from CDROM).
+Caution 2: A similar reset occurs when the user pushes the Analog button; this
+is causing rumble motors to be stopped and locked, and of course, the
+analog/digital state gets changed.
+Caution 3: If config commands were used, and the user does then push the analog
+button, then the 5Ah-byte gets replaced by 00h (ie. responses change from "HiZ
+id 5Ah ..." to "HiZ id 00h ...").
+
+ ____________________________ Config Mode Commands ____________________________
+
+Config Mode - Command 42h "B" - Read Buttons AND analog inputs
+ Send 01h 42h 00h M2 M1 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah buttons analog-inputs
+Same as command 42h in normal mode, but with forced analog response (ie. analog
+inputs and L3/R3 buttons are returned even in Digital Mode with LED=Off).
+
+Config Mode - Command 43h "C" - Enter/Exit Configuration Mode
+ Send 01h 43h 00h xx 00h 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah 00h 00h 00h 00h 00h 00h
+Equivalent to command 43h in normal mode, but returning 00h bytes rather than
+button data, can be used to return to normal mode.
+ xx=00h Enter Normal mode (Exit Configuration mode)
+ xx=01h Stay in Configuration mode
+Back in normal mode, the rumble motors (if they were enabled) can be controlled
+with normal command 42h.
+
+Config Mode - Command 44h "D" - Set LED State (analog mode on/off)
+ Send 01h 44h 00h Led Key 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah 00h 00h Err 00h 00h 00h
+The Led byte can be:
+ When Led=00h --> Digital mode, with LED=Off
+ When Led=01h --> Analog mode, with LED=On/red
+ When Led=02h..FFh --> Ignored (and, in case of dualshock2: set Err=FFh)
+The Key byte can be:
+ When Key=00h..02h --> Unlock (allow user to push Analog button)
+ When Key=03h --> Lock (stay in current mode, ignore Analog button)
+ When Key=04h..FFh --> Acts same as (Key AND 03h)
+The Err byte is usually 00h (except, Dualshock2 sets Err=FFh upon Led=02h..FFh;
+older PSX/PSone controllers don't do that).
+
+Config Mode - Command 45h "E" - Get LED State (and Type/constants)
+ Send 01h 45h 00h 00h 00h 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah Typ 02h Led 02h 01h 00h
+Returns two interesting bytes:
+ Led: Current LED State (00h=Off, 01h=On/red)
+ Typ: Controller Type (01h=PSX/Analog Pad, 03h=PS2/Dualshock2)
+The other bytes might indicate the number of rumble motors, analog sticks, or
+version information, or so.
+
+Config Mode - Command 46h "F" - Get Variable Response A
+ Send 01h 46h 00h ii 00h 00h 00h 00h 00h
+ Reply Hiz F3h 5Ah 00h 00h cc dd ee ff
+When ii=00h --> returns cc,dd,ee,ff = 01h,02h,00h,0ah
+When ii=01h --> returns cc,dd,ee,ff = 01h,01h,01h,14h
+Otherwise --> returns cc,dd,ee,ff = all zeroes
+
+Config Mode - Command 47h "G" - Get whatever values
+ Send 01h 47h 00h 00h 00h 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah 00h 00h 02h 00h 01h 00h
+Purpose unknown.
+
+Config Mode - Command 4Ch "L" - Get Variable Response B
+ Send 01h 4Ch 00h ii 00h 00h 00h 00h 00h
+ Reply Hiz F3h 5Ah 00h 00h 00h dd 00h 00h
+When ii=00h --> returns dd=04h.
+When ii=01h --> returns dd=07h.
+Otherwise --> returns dd=00h.
+
+Config Mode - Command 48h "H" - Unknown (response HiZ F3h 5Ah 4x00h 01h 00h)
+ Send 01h 48h 00h ii 00h 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah 00h 00h 00h 00h ee 00h
+When ii=00h..01h --> returns ee=01h.
+Otherwise --> returns ee=00h.
+Purpose unknown. The command does not seem to be used by any games.
+
+Config Mode - Command 4Dh "M" - Get/Set RumbleProtocol
+--> Controllers - Vibration/Rumble Control
+
+Config Mode - Command 40h "@" Dualshock2: Get/Set ButtonAttr?
+Config Mode - Command 41h "A" Dualshock2: Get Reply Capabilities
+Config Mode - Command 4Fh "O" Dualshock2: Set ReplyProtocol
+--> Controllers - Analog Buttons (Dualshock2)
+
+Config Mode - Command 49h "I" - Unused
+Config Mode - Command 4Ah "J" - Unused
+Config Mode - Command 4Bh "K" - Unused
+Config Mode - Command 4Eh "N" - Unused
+Config Mode - Command 40h "@" - Unused (except, used by Dualshock2)
+Config Mode - Command 41h "A" - Unused (except, used by Dualshock2)
+Config Mode - Command 4Fh "O" - Unused (except, used by Dualshock2)
+ Send 01h 4xh 00h 00h 00h 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah 00h 00h 00h 00h 00h 00h
+These commands do return a bunch of 00h bytes. These commands do not seem to be
+used by any games (apart from the Dualshock2 commands being used by Dualshock2
+games).
+
+Note
+Something called "Guitar Hero controller" does reportedly also support Config
+commands. Unknown if that thing does have the same inputs & rumble motors as
+normal analog PSX joypads, and if it does return special type values.
+
+Controllers - Vibration/Rumble Control
+--------------------------------------
+
+Rumble (aka "Vibration Function") is basically controlled by two previously
+unused bytes of the standard controller Read command.
+There are two methods to control the rumble motors, the old method is very
+simple (but supports only one motor), the new method envolves a bunch of new
+configuration commands (and supports two motors).
+ SCPH-1150 DualAnalog Pad with 1 motor ;-old rumble method
+ SCPH-1200 DualAnalog Pad with 2 motors, PSX-design ;\new rumble method
+ SCPH-110 DualAnalog Pad with 2 motors, PSone-design ;/
+ SCPH-10010 DualAnalog Pad with 2 motors, PS2/Dualshock2 ;-plus analog buttons
+ Blaze Scorpion Lightgun with rumble ;\unknow how to control rumble
+ Fishing controllers with rumble ;/
+ SCPH-1180 Analog Pad without rumble ;\unknow if there're config commands
+ SCPH-1110 Analog Stick without rumble ;/for analog mode (probably not)
+
+ _________________________________ Old Method _________________________________
+
+Old Method, one motor, no config commands (SCPH-1150, SCPH-1200, SCPH-110)
+The SCPH-1150 doesn't support any special config commands, instead, rumble is
+solely done via the normal joypad read command:
+ Send 01h 42h 00h xx yy (00h 00h 00h 00h)
+ Reply HiZ id 5Ah buttons ( analog-inputs )
+The rumble motor is simply controlled by three bits in the xx/yy bytes:
+ xx --> must be 40h..7Fh (ie. bit7=0, bit6=1) ;\switches motor on
+ yy --> must be 01h,03h,...,FDh,FFh (ie. bit0=1) ;/
+The motor control is digital on/off (no analog slow/fast), recommended values
+would be yyxx=0140h=on, and yyxx=0000h=off.
+LED state is don't care (rumble works with led OFF, RED, and GREEN). In absence
+of config commands, the LED can be controlled only manually (via Analog
+button), the current LED state is implied in the controller "id" byte.
+For backwards compatibility, the above old method does also work on SCPH-1200
+and SCPH-110 (for controlling the right/small motor), alternately those newer
+pads can use the config commands (for gaining access to both motors).
+
+ _________________________________ New Method _________________________________
+
+New Method, two motors, with config commands (SCPH-1200, SCPH-110)
+For using the new rumble method, one must unlock the new rumble mode, for that
+purpose Sony has invented a "slightly" overcomplicated protocol with not less
+than 16 new commands (the rumble relevant commands are 43h and 4Dh, also,
+command 44h may be useful for activating analog inputs by software, and, once
+when rumble is unlocked, command 42h is used to control the rumble motors).
+Anyways, here's the full command set...
+Controllers - Configuration Commands
+And, the rumble-specific config command is described below...
+
+Config Mode - Command 4Dh "M" - Get/Set RumbleProtocol
+ Send 01h 4Dh 00h aa bb cc dd ee ff ;<-- set NEW aa..ff values
+ Reply Hiz F3h 5Ah aa bb cc dd ee ff ;<-- returns OLD aa..ff values
+Bytes aa,bb,cc,dd,ee,ff control the meaning of the 4th,5th,6th,7th,8th,9th
+command byte in the controller read command (Command 42h).
+ 00h = Map Right/small Motor (Motor M2) to bit0 of this byte
+ 01h = Map Left/Large Motor (Motor M1) to bit0-7 of this byte
+ 02h..FEh = Unknown (can be mapped, maybe for extra motors/outputs)
+ FFh = Map nothing to this byte
+In practice, one would usually send either one of these command/values:
+ Send 01h 4Dh 00h 00h 01h FFh FFh FFh FFh ;enable new method (two motors)
+ Send 01h 4Dh 00h FFh FFh FFh FFh FFh FFh ;disable motor control
+Alternately, one could swap the motors by swapping values in aa/bb. Or one
+could map the motors anywhere to cc/dd/ee/ff (this will increase the command
+length in digital mode, hence changing digital mode ID from 41h to 42h or 43h).
+Or, one could map further rumble motors or other outputs to the six bytes (if
+any such controller would exist).
+In the initial state, aa..ff are all FFh, and the controller does then use the
+old rumble control method (with only one motor). However, that old method gets
+disabled once when having messed with config commands (unknown if/how one can
+re-enable the old method by software).
+
+Unknown Dualshock2 Vibration
+Dualshock2 does reportedly have "two more levels of vibration", unknown what
+that means and if it's used by any PSX or PS2 games... it might refer to the
+small motor which usually has only 2 levels (on/off) and might have 4 levels
+(fast/med/slow/off) on dualshock2... but, if so, it's unknown how to
+control/unlock that feature.
+Also, the PSone controller (SCPH-110) appear to have been released shortly
+after Dualshock2, unknown if that means that it might have that feature, too.
+
+Note
+Rumble is a potentially annoying feature, so games that do support rumble
+should also include an option to disable it.
+
+Controllers - Analog Buttons (Dualshock2)
+-----------------------------------------
+
+Dualshock2 has three new commands (40h,41h,4Fh) for configuring analog buttons.
+Additionally, Command 45h does return a different type byte for Dualshock2.
+Dualshock2 is a PS2 controller. However, it can be also used with PSX games
+(either by connecting the controller to a PSX console, or by playing a PSX game
+on a PS2 console).
+The analog button feature is reportedly rarely used by PS2 games (and there
+aren't any PSX games known to use it).
+
+Config Mode - Command 40h "@" Dualshock2: Get/Set ButtonAttr?
+ Send 01h 40h 00h Idx Val 00h 00h 00h 00h ;<-- Set NEW Val, array[Idx]=Val
+ Reply HiZ F3h 5Ah 00h 00h Val 00h 00h 00h ;<-- Old Val (or FFh when Idx>0Bh)
+Allows to change twelve 3bit values (with Idx=00h..0Bh, and Val=00h..03h).
+Default is Val=02h. Purpose is unknown, the 12 values might be related to the
+12 analog buttons, but there is no noticable difference between Val=0,1,2,3.
+Maybe it does have some subtle effects on things like...
+ Digital button sensitivity, or Analog button sensitivity, or
+ Analog button bit-depth/conversion speed, or something else?
+
+Config Mode - Command 41h "A" Dualshock2: Get Reply Capabilities
+ Send 01h 41h 00h 00h 00h 00h 00h 00h 00h
+ Reply HiZ F3h 5Ah FFh FFh 03h 00h 00h 00h
+This seems to return a constant bitmask indicating which reply bytes can be
+enabled/disabled via Command 4Fh (ie. 3FFFFh = 18 bits).
+
+Config Mode - Command 4Fh "O" Dualshock2: Set ReplyProtocol
+ Send 01h 41h 00h aa bb cc dd ee ff
+ Reply HiZ F3h 5Ah 00h 00h 00h 00h 00h 00h
+This can output some 48bit value (bit0=aa.bit0, bit47=ff.bit7), used to
+enable/disable Reply bytes in the controller read command (Command 42h).
+ - HighZ (always transferred) 1st byte
+ - ID/Mode/Len (always transferred) 2nd byte
+ - 5Ah (always transferred) 3rd byte
+ 0 LSB of digital buttons (0=No, 1=Yes) 4th byte
+ 1 MSB of digital buttons (0=No, 1=Yes) 5th byte
+ 2 RightJoyX (0=No, 1=Yes) 6th byte
+ 3 RightJoyY (0=No, 1=Yes) 7th byte
+ 4 LeftJoyX (0=No, 1=Yes) 8th byte
+ 5 LeftJoyY (0=No, 1=Yes) 9th byte
+ 6 DPAD Right (0=No, 1=Yes) button 00h 10th byte
+ 7 DPAD Left (0=No, 1=Yes) button 01h 11th byte
+ 8 DPAD Uup (0=No, 1=Yes) button 02h 12th byte
+ 9 DPAD Down (0=No, 1=Yes) button 03h 13th byte
+ 10 Button /\ (0=No, 1=Yes) button 04h 14th byte
+ 11 Button () (0=No, 1=Yes) button 05h 15th byte
+ 12 Button >< (0=No, 1=Yes) button 06h 16th byte
+ 13 Button [] (0=No, 1=Yes) button 07h 17th byte
+ 14 Button L1 (0=No, 1=Yes) button 08h 18th byte
+ 15 Button R1 (0=No, 1=Yes) button 09h 19th byte
+ 16 Button L2 (0=No, 1=Yes) button 0Ah 20th byte
+ 17 Button R2 (0=No, 1=Yes) button 0Bh 21st byte
+ 18-39 Must be 0 (otherwise command is ignored)
+ 40-47 Unknown (no effect?)
+Usually, one would use one of the following command/values:
+ Send 01h 41h 00h 03h 00h 00h 00h 00h 00h Digital buttons
+ Send 01h 41h 00h 3Fh 00h 00h 00h 00h 00h Digital buttons + analog sticks
+ Send 01h 41h 00h FFh FFh 03h 00h 00h 00h Enable all 18 input bytes
+The transfer order is 1st..21st byte as shown above (unless some bits are
+cleared, eg. if bit0-5=0 and bit6=1 then DPAD Right would appear as 4th byte
+instead of 10th byte). The command length increases/decreases depening on the
+number of enabled bits. The transfer length is always 3+N*2 bytes (including a
+00h padding byte when the number of enabled bits is odd). The analog mode ID
+byte changes depending on number of halfwords.
+CAUTION: Sending Command 44h does RESET the Command 4Fh setting (either to
+DigitalMode=000003h or AnalogMode=00003Fh; same happens when toggling mode via
+Analog button).
+
+Note: Some Dualshock2 Config Mode commands do occassionally send 00h, 5Ah, or
+FFh as last (9th) reply byte (unknown if that is some error/status thing, or
+garbage).
+
+Analog Button Sensitivity
+The pressure sensors are rather imprecise and results may vary on various
+factors, including the pressure angle.
+ 00h Button released
+ 01h..2Fh Normal (soft) pressure
+ 30h..FEh Medium pressure
+ FFh Hard pressure
+Software can safely distinguish between soft and hard pressure.
+Medium pressure is less predictably: The values do not increase linearily, it's
+difficult to apply a specific amount of medium pressure (such like 80h..9Fh),
+increasing pressure may sometimes jump from 24h to FFh, completely skipping the
+medium range.
+Relying on the medium range might work for accelleration buttons (where the
+user could still adjust the pressure when the accelleration is too high or too
+low); but it would be very bad practice to assign irreversible actions to
+medium pressure (such like Soft=Load, Medium=Save, Hard=Quit).
+
+Digital Button Sensitivity
+Digital inputs are converting the analog inputs as so:
+ Analog=00h --> not pressed
+ Analog=01h..FFh --> pressed (no matter if soft, medium, or hard pressure)
+Digital inputs are working even when also having analog input enabled for the
+same button.
+
+See also
+ https://gist.github.com/scanlime/5042071 - tech (=mentions unknown details)
+ https://store.curiousinventor.com/guides/PS2/ - guide (=omits unknown stuff)
+
+Controllers - Dance Mats
+------------------------
+
+PSX Dance Mats are essentially normal joypads with uncommonly arranged buttons,
+the huge mats are meant to be put on the floor, so the user could step on them.
+
+Dance Mat vs Joypad Compatibility
+There are some differences to normal joypads: First of, the L1/L2/R1/R2
+shoulder buttons are missing in most variants. And, the mats are allowing to
+push Left+Right and Up+Down at once, combinations that aren't mechanically
+possible on normal joypads (some dancing games do actually require those
+combinations, whilst some joypad games may get confused on them).
+
+Dance Mat Unknown Things
+Unknown if the mat was sold in japan, and if so, with which SLPH/SCPH number.
+Unknown if the mat's middle field is also having a button assigned.
+Unknown if the mat is having a special controller ID, or if there are other
+ways to detect mats (the mats are said to be compatible with skateboard games,
+so the mats are probably identifying themselves as normal digital joypad;
+assuming that those skateboard games haven't been specifically designed for
+mats).
+
+Dance Mat Games
+ D.D.R. Dance Dance Revolution 2nd Remix
+ (and maybe whatever further games)
+The mats can be reportedly also used with whatever skateboard games.
+
+Dance Mat Variants
+There is the US version (DDR Dance Pad, SLUH-00071), and a slightly different
+European version (Official Dance Mat, SLEH-00023: shiny latex style with
+perverted colors, and Start/Select arranged differently). The japanese version
+(RU017) resembles the US version, but without Triangle/Square symbols drawn in
+lower left/right edges.
+And there is a handheld version (with additional L1/L2/R2/R1 buttons; maybe
+unlicensed; produced as MINI DDR, and also as Venom Mini Dance Pad).
+
+ US Version (white/black/red/blue) Handheld Version (blue/gray)
+ __________.---------.___________ _____/ MINI \_____
+ | \ / | | D.D.R. |
+ | SELECT '-------' START | |L1 L2 SEL STA R2 R1|
+ |------------.------.------------| | ___ ___ ___ |
+ | .''''. / \ .''''. | || X | | ^ | | O ||
+ | | \/ | | /\ | | .''. | | ||___| |___| |___||
+ | | /\ | | /..\ | | '..' | | | ___ .---. ___ |
+ | '....' '. || .' '....' | || < | |Stay | | > ||
+ | .-------. .''''''''. .-------. | ||___| |Cool!| |___||
+ |/ /| .' '. |\ \| | ___ '___' ___ |
+ | / |-- | | --| \ | || []| | v | | /\||
+ | \ |-- | Stay Cool! | --| / | ||___| |___| |___||
+ |\ \| '. .' |/ /| |___________________|
+ | '-------' '........' '-------' |
+ | .''''. .' || '. .''''. | Gothic Dance Mat (black/silver)
+ | | /\ | | \''/ | | |''| | | _.----------._
+ | | /__\ | | \/ | | |..| | | | \ SEL STA / | This one
+ | '....' \ / '....' | | '--------' | wasn't ever
+ '------------'------'------------' | .----------. | produced,
+ | | .''''. | | as cool as
+ European Version (pink/blue/yellow) | | | /\ | | | it could have
+ __________.---------.___________ | | | /..\ | | | been, the lame
+ | \ SEL STA / | | | '.||.' | | marketing
+ | '-------' | | +----------+ | people didn't
+ |----------.----------.----------| | | .''''. | | even think
+ | .''''. | .''''. | .''''. | | | | /\ | | | about it.
+ | | \/ | | | /\ | | | .''. | | | | | /..\ | | |
+ | | /\ | | | /..\ | | | '..' | | | | '.||.' | |
+ | '....' | '.||.' | '....' | | +----------+ |
+ |----------+-.. ..-+----------| | | .'||'. | |
+ | .'/|'. / '''' \ .'|\'. | | | | \''/ | | |
+ | | / |--|/ \|--| \ | | | | | \/ | | |
+ | | \ |--|\ /|--| / | | | | '....' | |
+ | '.\|.' \ .... / '.|/.' | | +----------+ |
+ |----------+-'' ''-+----------| | | .'||'. | |
+ | .''''. | .'||'. | .''''. | | | | \''/ | | |
+ | | /\ | | | \''/ | | | |''| | | | | | \/ | | |
+ | | /__\ | | | \/ | | | |..| | | | | '....' | |
+ | '....' | '....' | '....' | | '----------' '
+ '----------|----------|----------' '--------------'
+
+Stay Cool?
+Despite of the "Stay Cool!" slogan, the mat wasn't very cool - not at all! It
+offered only two steps back-and-forth, and also allowed to do extremly uncool
+side-steps. Not to mention that it would melt when dropping a burning cigarette
+on it. Stay Away!
+
+Controllers - Fishing Controllers
+---------------------------------
+
+The fishing rods are (next to lightguns) some of the more openly martial
+playstation controllers - using the credo that "as long as you aren't using
+dynamite: it's okay to kill them cause they don't have any feelings."
+
+PSX Fishing Controller Games
+ Action Bass (Syscom Entertainment) (1999) (SLPH-00100)
+ Bass Landing (ASCII/agetec) (1999) (SLPH-00100, SLUH-00063)
+ Bass Rise, Fishing Freaks (Bandai) (1999) (BANC-0001)
+ Bass Rise Plus, Fishing Freaks (Bandai) (2000) (BANC-0001, SLPH-00100)
+ Breath of Fire IV (Capcom) (SLUH-00063)
+ Championship Bass (EA Sports) (2000) (SLUH-00063)
+ Fish On! Bass (Pony Canyon) (1999) (BANC-0001, SLPH-00100)
+ Fisherman's Bait 2/Exiting Bass2 - Big Ol'Bass(Konami)(SLPH-00100,SLUH-00063)
+ Fishing Club: (series with 3 titles) (have "headset-logo" on back?)
+ Lake Masters II (1999) (Dazz/Nexus) (SLPH-00100)
+ Lake Masters Pro (1999) (Dazz/Nexus) (BANC-0001, SLPH-00100)
+ Let's Go Bassfishing!: Bass Tsuri ni Ikou! (Banpresto) (1999) (SLPH-00100)
+ Matsukata Hiroki no World Fishing (BPS The Choice) (1999) (SLPH-00100)
+ Murakoshi Seikai-Bakuchou Nihon Rettou (Victor) (SLPH-00100)
+ Murakoshi Masami-Bakuchou Nippon Rettou:TsuriConEdition (1999) (SLPH-00100)
+ Pakuchikou Seabass Fishing (JP, 03/25/99) (Victor) (SLPH-00100)
+ Perfect Fishing: Bass Fishing (2000) (Seta) (yellow/green logo)
+ Perfect Fishing: Rock Fishing (2000) (Seta) (yellow/green logo)
+ Oyaji no Jikan: Nechan, Tsuri Iku De! (2000) (Visit) (BANC-0001, SLPH-00100)
+ Reel Fishing II / Fish Eyes II (2000)(Natsume/Victor)(SLPH-00100, SLUH-00063)
+ Simple 1500 Series Vol. 29: The Tsuri (2000) (yellow/green logo)
+ Suizokukan Project: Fish Hunter e no Michi (1999)(Teichiku)(SLPH-00100)
+ Super Bass Fishing (1999) (King) (BANC-0001, SLPH-00100, yellow/green logo)
+ Super Black Bass X2 (2000) (Starfish) (SLPH-00100)
+ Tsuwadou Keiryuu Mizuumihen (Best Edition)(2000) (ASCII PS1+PS2 controllers?)
+ Tsuwadou Seabass Fishing (PlayStation the Best) (1999) (Oz Club) (SLPH-00100)
+ Uki Uki Tsuri Tengoku Nagami/Uokami Densetsu Oe (2000) (Teichiku)(SLPH-00100)
+ Umi no Nushi Tsuri-Takarajima ni Mukatte (1999)(Victor)(BANC-0001,SLPH-00100)
+ Winning Lure (Hori) (2000) (for Hori HPS-97 controller) AKA HPS-98 ?
+For more see: http://www.gamefaqs.com/ps/list-109 (sports->nature->fishing)
+
+Logos on CD Covers
+US Fishing games should have a "SLUH-00063" logo. European Fishing games don't
+have any fishing logos; apparently fishing controllers haven't been officially
+released/supported in Europe.
+Japanese Fishing games can have a bunch of logos: Usually BANC-0001 or
+SLPH-00100 (or both).
+Moreover, some japanese games have a yellow/green fishing logo with japanese
+text (found on Perfect Fishing: Bass Fishing, Perfect Fishing: Rock Fishing,
+Simple 1500 Series Vol. 29: The Tsuri, Super Bass Fishing) (unknown if that
+logo refer to other special hardware, or if it means the "normal" BANC-0001 or
+SLPH-00100 controllers.
+And Moreover, some japanese games have some sort of "headset" logos with
+japanese text, these seem to have same meaning as SLPH-00100; as indicated by
+photos on CD cover of Tsuwadou Keiryuu Mizuumihen (Best Edition) (2000); that
+CD cover also has a "headset 2" logo, which seems to mean a newer PS2 variant
+of the SLPH-00100.
+
+PSX Fishing Controllers
+ ASCII SLPH-00100 (silver)
+ ASCII PS2-version? (silver) (similar to SLPH-00100, with new mode switch?)
+ agetec SLUS-00063 (silver) (US version of ASCII's SLPH-00100 controller)
+ Bandai BANC-0001 (dark gray/blue) (has less buttons than ASCII/agetec)
+ Interact Fission (light gray/blue)(similar to ASCII/agetec, 2 extra buttons?)
+ Naki (transparent blue) (looks like a clone of the ASCII/agetec controllers)
+ Hori HPS-97/HPS-98 (black/gray) (a fishing rod attached to a plastic fish)
+Of these, the ASCII/agetec controllers seem to be most popular (and most
+commonly supported). The Bandai contoller is also supported by a couple of
+games (though the Bandai controller itself seems to be quite rare). The
+Interact/Naki controllers are probably just clones of the ASCII/agetec ones.
+The Hori controller is quite rare (and with its string and plastic fish, it's
+apparently working completely different than the other fishing controllers).
+
+Tech Info (all unknown)
+Unknown how to detect fishing controllers.
+Unknown how to read buttons, joystick, crank, motion sensors.
+Unknown how to control rumble/vibration.
+Unknown if/how Bandai differs from ASCII/agetec (aside from less buttons).
+Unknown how the Hori thing works.
+
+ASCII SLPH-00100 / agetec SLUH-00063 (silver)
+ ___
+ __|___|__
+ _| |_ _ __
+ | | | | | |=|__| <--- crank handle
+ | | SEL STA | | | |
+ | | | |---| \ ASCII SLPH-00100
+ | \ / |---| / agetec SLUH-00063
+ / L1 R1 \ | | __
+ | L2 .---. R2 | |_|=|__|
+ | | joy | |
+ | |stick| | <------- analog thumb controlled joystick
+ | /\ '---' >< |
+ | [] () |
+ \ ASCII /
+ '.___________.' \___ 10 buttons (SEL,STA,L1,L2,R1,R2,/\,[],(),><)
+ \ _____ /
+ | | Note: many (not all) agetec controllers
+ | | have the >< and () buttons exchanged
+ | |
+ | | Aside from the crank/buttons/joystick,
+ | | the controller reportedly contains:
+ | | some sort of motion sensors?
+ | | some kind of rumble/vibration?
+ | |
+ '.___.'
+ '--...___ cable
+
+Bandai BANC-0001 (dark gray/blue)
+ ___
+ __|___|__
+ _| | _ __
+ | .---. |\ | |=|__| <--- crank handle
+ || joy | | | | |
+ ||stick| | |-#-| \
+ | '---' | |-#-| /
+ / \ | \ | | __
+ | | ... | | |_|=|__|
+ | | : : | ()|
+ | |O :___: O| | <--- two buttons: () and ><
+ | |- |___| -| ><| and some slide switch with I and 0 positions?
+ | | | |
+ \ | BANDAI | / unknown if the joystick is digital or analog
+ '._\_______/_.'
+ | | unknown if there are motion sensors and/or rumble
+ '. .'
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ | |
+ '.___.'
+ '--...___ cable
+
+Hori HPS-97 / HPS-98 (black/gray)
+ ....----------------O
+ .'' \ HPS-97 (controller bundled with game)
+ _:_ \ \ HPS-98 (controller only, for HPS-96 game)
+ __|___|__ \ short \
+ _| |_ elastic \
+ | | pole \
+ | | \ <--- string (from pole to
+ | SW? | _ __ \ reel inside of fish)
+ / \ | |=|__| \
+ | .---. | | | \
+ | ( ) | joy | |--| \ \ ___
+ | |stick| |--| / \ / /
+ | ( ) '---' | | | __ \ ...---''''''--. /|
+ | | |_|=|__| <--- crank \ ' '/ |
+ \ ( ) ( ) / handle '..| |.
+ '.___________.' |__________________| :
+ \ / \ plastic fish :
+ | | joystick, (presumable some heavy :
+ | | four buttons, stationary thing that :
+ | | and a switch? rests on floor) :
+ | | (presumably with :
+ | | motor-driven reel?) :
+ | | :
+ | | the two cables do probably connect :
+ | | to both of the PSX controller slots :
+ '.___.' cable 2 ---'
+ '--...___ cable 1
+
+Controllers - I-Mode Adaptor (Mobile Internet)
+----------------------------------------------
+
+The I-Mode Adaptor cable (SCPH-10180) allows to connect an I-mode compatible
+mobile phone to the playstation's controller port; granting a mobile internet
+connection to japanese games.
+
+PSX Games for I-Mode Adaptor (Japan only)
+ Doko Demo Issyo (PlayStation the Best release only) (Sony) 2000
+ Doko Demo Issyo Deluxe Pack (Bomber eXpress/Sony) 2001
+ Hamster Club-I (SLPS-03266) (Jorudan) 2002
+ iMode mo Issyo: Dokodemo Issho Tsuika Disc (Bomber/Sony) 2001
+ Keitai Eddy (iPC) 2000 (but, phone connects to SIO port on REAR side of PSX?)
+ Komocchi (Victor) 2001
+ Mobile Tomodachi (Hamster) 2002
+ Motto Trump Shiyouyo! i-Mode de Grand Prix (Pure Sound) 2002
+ One Piece Mansion (Capcom) 2001 (japanese version only)
+The supported games should have a I-Mode adaptor logo on the CD cover (the logo
+depicts two plugs: the PSX controller plug, and the smaller I-Mode plug).
+Note: "Dragon Quest Monsters 1 & 2" was announced/rumoured to support I-mode
+(however, its CD cover doesn't show any I-Mode adapter logo).
+
+Tech Details (all unknown)
+Unknown how to detect the thing, and how to do the actual data transfers.
+The cable does contain a 64pin chip, an oscillator, and some smaller components
+(inside of the PSX controller port connector).
+
+Hardware Variant
+Keitai Eddy seems to have the phone connect to the SIO port (on rear side of
+the PSX, at least it's depicted like so on the CD cover). This is apparently
+something different than the SCPH-10180 controller-port cable. Unknown what it
+is exactly - probably some mobile internet connection too, maybe also using
+I-mode, or maybe some other protocol.
+
+Controllers - Keyboards
+-----------------------
+
+There isn't any official retail keyboard for PSX, however, there is a shitload
+of obscure ways to connect keyboards...
+
+Sony SCPH-2000 PS/2 Keyboard/Mouse Adaptor (prototype/with cable) (undated)
+Sony SCPH-2000 PS/2 Keyboard/Mouse Adaptor (without cable) (undated)
+A PS/2 to PSX controller port adaptor. Maybe for educational Lightspan titles?
+There are two hardware variants of the adaptor:
+ Adaptor with short cable to PSX-controller port (and prototype marking)
+ Adaptor without cable, directly plugged into controller port (final version?)
+Unknown ^how to access those adaptors, and unknown if the two versions differ
+at software side. There seem to be not much more than a handful of people
+owning that adaptors, and none of them seems to know how to use it, or even how
+to test if it's working with existing software...
+- Keyboard reading might work with the Online Connection CD.
+- Mouse reading might work with normal mouse compatible PSX games.
+
+Lightspan Online Connection CD Keyboard (1997)
+The Online Connection CD is a web browser from the educational Lightspan
+series, the CD is extremly rare (there's only one known copy of the disc).
+The thing requires a dial-up modem connected to the serial port (maybe simply
+using the same RS232 adaptor as used by Yaroze). User input can be done via
+joypad, or optionally, via some external keyboard (or keyboard adaptor)
+hardware:
+ Send 01h 42h 00h 00h 00h 00h 00h 00h 00h 00h 00h 00h 00h 00h 06h
+ Reply HiZ 96h 5Ah num dat dat dat dat dat dat dat dat dat dat dat
+The num byte indicates number of following scancodes (can be num=FFh, maybe
+when no keyboard connected?, or num=00h..0Bh for max 11 bytes, unless the last
+some bytes should have other meaning, like status/mouse data or so).
+The keyboard scancodes are in "PS/2 Keyboard Scan Code Set 2" format.
+The binary contains some (unused) code for sending data to the keyboard by
+changing the 4th-11th byte, and resuming normal operation by setting 4th and
+11th byte back to zero:
+ Send .. .. .. 01h xxh FFh FFh FFh FFh FFh 00h .. .. .. ..
+ Send .. .. .. 00h .. .. .. .. .. .. 00h .. .. .. ..
+Maybe 4th and 11th byte are number of following bytes, with xxh being some
+command, and FFh's just being bogus padding; the xxh looks more like an
+incrementing value though.
+Despite of the mouse-based GUI, the browser software doesn't seem to support
+mouse hardware (neither via PS/2 mice, nor PSX mice). Instead, the mouse arrow
+can be merely moved via joypad's DPAD, or (in a very clumsy fashion) via
+keyboard cursor keys.
+Note: The browser uses SysEnqIntRP to install some weird IRQ handler that
+forcefully aborts all controller (or memory card) transfers upon Vblank.
+Unknown if that's somehow required to bypass bugs in the keyboard hardware. The
+feature is kinda dangerous for memory card access (especially with fast memcard
+access in nocash kernel, which allows to transfer more than one sector per
+frame).
+
+Spectrum Emulator Keyboard Adaptor (v1/serial port) (undated)
+Made by Anthony Ball. http://www.sinistersoft.com/psxkeyboard
+ [1F801058h]=00CEh ;SIO_MODE 8bit, no parity, 2 stop bits (8N2)
+ [1F80105Ah]=771Ch ;SIO_CTRL rx enable (plus whatever nonsense bits)
+ [1F80105Eh]=006Ch ;SIO_BAUD 19200 bps
+ RX Keyboard Scancode (same ASCII-style as in later versions?)
+ CTS Caps-Lock state
+ DSR Num-Lock state
+
+Spectrum Emulator Keyboard & Sega Sticks Adaptor (v2/controller port) (2000)
+Made by Anthony Ball. http://www.sinistersoft.com/psxkeyboard
+This adaptor can send pad/stick data,
+ Send 01h 42h 00h 0h 0h
+ Reply HiZ 41h 5Ah PadA
+as well as pad/sticks+keyboard data,
+ Send 01h 42h 00h 0h 0h 0h 0h 0h 0h 0h 0h 00h 00h 0h 0h 0h 0h 0h 0h
+ Reply HiZ E8h 5Ah PadA PadB PadC PadD Ver Lock Buffer(0..5)
+The above mode(s) can be switched via ACPI Power/Sleep/Wake keys (on keyboards
+that do have such keys).
+ Version=1 ; version number
+ 0 SCROLL ; scroll lock on
+ 1 NUM ; num lock on
+ 2 CAPS ; caps lock on
+ 3 DONETEST ; keyboard has just done a selftest
+ 4 EMUA ; emulation mode a
+ 5 EMUB ; emulation mode b
+For whatever reason, the PS/2 scancodes are translated to ASCII-style scancode
+values (with bit7=KeyUp flag):
+ 01 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 69 1F
+ 60 21 22 68 24 25 5E 26 2A 28 29 5F 3D 2D 0B 0E 0F 67 2F 1E 2D
+ 27 51 57 45 52 54 59 55 49 4F 50 5B 5D 0D 10 61 62 37 38 39
+ 3B 41 53 44 46 47 48 4A 4B 4C 3A 40 23 34 35 36 2B
+ 02 5C 5A 58 43 56 42 4E 4D 3C 3E 3F 03 63 31 32 33
+ 04 05 06 20 07 08 09 0A 65 64 66 30 2E 6A
+BUG: The thing conflicts with memory cards: It responds to ANY byte with value
+01h (it should do so only if the FIRST byte is 01h).
+
+Homebrew PS/2 Keyboard/Mouse Adaptor (undated/from PSone era)
+ Send 01h 42h 00h 00h 00h 00h 00h
+ Reply HiZ 12h 5Ah key flg dx dy
+flg:
+ bit0-1 = Always 11b (unlike Sony mouse)
+ bit2 = Left Mouse Button (0=Pressed, 1=Released)
+ bit3 = Right Mouse Button (0=Pressed, 1=Released)
+ bit4-5 = Always 11b (like Sony mouse)
+ bit6 = Key Release (aka F0h prefix) (0=Yes)
+ bit7 = Key Extended (aka E0h prefix) (0=Yes)
+Made by Simon Armstrong. This thing emulates a standard PSX Mouse (and should
+thus work with most or all mouse compatible games). Additionally, it's sending
+keyboard flags/scancodes via unused mouse button bits.
+
+Runix hardware add-on USB Keyboard/Mouse Adaptor (2001) (PIO extension port)
+Runix is a homebrew linux kernel for PSX, it can be considered being the holy
+grail of the open source scene because nobody has successfully compiled it in
+the past 16 years.
+- USB host controller SL811H driver with keyboard and mouse support;
+- RTC support.
+file: drivers/usb/sl811h.c
+
+TTY Console
+The PSX kernel allows to output "printf" debug messages via stdout. In the
+opposite direction, it's supporting to receive ASCII user input via
+"std_in_gets" (there isn't any software actually using that feature though,
+except maybe debug consoles like DTL-H2000).
+
+Controllers - Additional Inputs
+-------------------------------
+
+Reset Button
+PSX only (not PSone). Reboots the PSX via /RESET signal. Probably including for
+forcefully getting through the WHOLE BIOS Intro, making it rather
+useless/annoying? No idea if it clears ALL memory during reboot?
+
+CDROM Shell Open
+Status bit of the CDROM controller. Can be used to sense if the shell is opened
+(and also memorizes if the shell was opened since last check; allowing to sense
+possible disk changes).
+
+PocketStation
+Memory Card with built-in LCD screen and Buttons (which can be used as
+miniature handheld console). However, when it is connected to the PSX, the
+buttons are vanishing in the cartridge slot, so the buttons cannot be used as
+additional inputs for PSX games.
+
+Serial Port PSX only (not PSone)
+With an external adaptor (voltage conversion), the serial port can be used
+(among others) to connect a RS232 Serial Mouse. Although, most or all
+commercial games with mouse input are probably (?) supporting only Sony's Mouse
+(on the controller port) (rather than standard RS232 devices on the serial
+port).
+
+TTY Debug Terminal
+If present, the external DUART can be used for external keyboard input, at the
+BIOS side, this is supported as "std_in".
+
+Controllers - Misc
+------------------
+
+Standard Controllers
+ SCPH-1010 digital joypad (with short cable)
+ SCPH-1080 digital joypad (with longer cable)
+ SCPH-1030 mouse (with short cable)
+ SCPH-1090 mouse (with longer cable)
+ SCPH-1092 mouse (european?)
+ SCPH-1110 analog joystick
+ SCPH-1150 analog joypad (with one vibration motor, with red/green led)
+ SCPH-1180 analog joypad (without vibration motors, with red/green led)
+ SCPH-1200 analog joypad (with two vibration motors) (dualshock)
+ SCPH-110 analog joypad (with two vibration motors) (dualshock for psone)
+ SCPH-10010 dualshock2 (analog buttons, except L3/R3/Start/Select) (for ps2)
+ SCPH-1070 multitap
+
+Special Controllers
+ SCPH-4010 VPick (guitar-pick controller) (for Quest for Fame, Stolen Song)
+SLPH-0001 (nejicon)
+BANDAI "BANC-0002" - 4 Buttons (Triangle, Circle, Cross, Square) (nothing more)
+
+Joystick
+ __________ __________
+ | | | ^ | ^
+ | L1 R1 | | X <+> O | <+> = Digital Stick
+ \ ___| <--- L2 [] ---> |___ v / v
+ | | <--- R2 /\ ---> | |
+ ___| |___________________________| |___ Not sure if all buttons
+ | | | SEL STA =?= | | | are shown at their
+ | | | | | | correct locations?
+ | | |_ [] /\ _| | | (drawing is based on
+ | _| / L1 R1 \ |_ | below riddle/lyrics)
+ | \_____/ X O \_____/ |
+ | /___\ L2 R2 /___\ |
+ | |
+ | |
+ \___________________________________________/
+
+ The thumb buttons on the left act as L1 and R1,
+ the trigger is L2, the pinky button is R2
+ The thumb buttons on the right act as X and O,
+ the trigger is Square and the pinky button is Triangle.
+ I find this odd as the triggers should've been L1 and R1,
+ the pinkies L2 and R2.
+ The buttons are redundantly placed on the base as large buttons like what
+ you'd see on a fight/arcade stick. Also with Start and Select.
+ There is also a physical analog mode switch,
+ not a button like on dual shock.
+
+Memory Card Read/Write Commands
+-------------------------------
+
+Reading Data from Memory Card
+ Send Reply Comment
+ 81h N/A Memory Card Access (unlike 01h=Controller access), dummy response
+ 52h FLAG Send Read Command (ASCII "R"), Receive FLAG Byte
+ 00h 5Ah Receive Memory Card ID1
+ 00h 5Dh Receive Memory Card ID2
+ MSB (00h) Send Address MSB ;\sector number (0..3FFh)
+ LSB (pre) Send Address LSB ;/
+ 00h 5Ch Receive Command Acknowledge 1 ;<-- late /ACK after this byte-pair
+ 00h 5Dh Receive Command Acknowledge 2
+ 00h MSB Receive Confirmed Address MSB
+ 00h LSB Receive Confirmed Address LSB
+ 00h ... Receive Data Sector (128 bytes)
+ 00h CHK Receive Checksum (MSB xor LSB xor Data bytes)
+ 00h 47h Receive Memory End Byte (should be always 47h="G"=Good for Read)
+Non-sony cards additionally send eight 5Ch bytes after the end flag.
+When sending an invalid sector number, original Sony memory cards respond with
+FFFFh as Confirmed Address (and do then abort the transfer without sending any
+data, checksum, or end flag), third-party memory cards typically respond with
+the sector number ANDed with 3FFh (and transfer the data for that adjusted
+sector number).
+
+Writing Data to Memory Card
+ Send Reply Comment
+ 81h N/A Memory Card Access (unlike 01h=Controller access), dummy response
+ 57h FLAG Send Write Command (ASCII "W"), Receive FLAG Byte
+ 00h 5Ah Receive Memory Card ID1
+ 00h 5Dh Receive Memory Card ID2
+ MSB (00h) Send Address MSB ;\sector number (0..3FFh)
+ LSB (pre) Send Address LSB ;/
+ ... (pre) Send Data Sector (128 bytes)
+ CHK (pre) Send Checksum (MSB xor LSB xor Data bytes)
+ 00h 5Ch Receive Command Acknowledge 1
+ 00h 5Dh Receive Command Acknowledge 2
+ 00h 4xh Receive Memory End Byte (47h=Good, 4Eh=BadChecksum, FFh=BadSector)
+
+Get Memory Card ID Command
+ Send Reply Comment
+ 81h N/A Memory Card Access (unlike 01h=Controller access), dummy response
+ 53h FLAG Send Get ID Command (ASCII "S"), Receive FLAG Byte
+ 00h 5Ah Receive Memory Card ID1
+ 00h 5Dh Receive Memory Card ID2
+ 00h 5Ch Receive Command Acknowledge 1
+ 00h 5Dh Receive Command Acknowledge 2
+ 00h 04h Receive 04h
+ 00h 00h Receive 00h
+ 00h 00h Receive 00h
+ 00h 80h Receive 80h
+This command is supported only by original Sony memory cards. Not sure if all
+sony cards are responding with the same values, and what meaning they have,
+might be number of sectors (0400h) and sector size (0080h) or whatever.
+
+Invalid Commands
+ Send Reply Comment
+ 81h N/A Memory Card Access (unlike 01h=Controller access), dummy response
+ xxh FLAG Send Invalid Command (anything else than "R", "W", or "S")
+Transfer aborts immediately after the faulty command byte, or, occasionally
+after one more byte (with response FFh to that extra byte).
+
+FLAG Byte
+The initial value of the FLAG byte on power-up (and when re-inserting the
+memory card) is 08h.
+Bit3=1 is indicating that the directory wasn't read yet (allowing to sense
+memory card changes). For some strange reason, bit3 is NOT reset when reading
+from the card, but rather when writing to it. To reset the flag, games are
+usually issuing a dummy write to sector number 003Fh, more or less
+unneccessarily stressing the lifetime of that sector.
+Bit2=1 seems to be intended to indicate write errors, however, the write
+command seems to be always finishing without setting that bit, instead, the
+error flag may get set on the NEXT command.
+Note: Some (not all) non-sony cards also have Bit5 of the FLAG byte set.
+
+Timings
+IRQ7 is usually triggered circa 1500 cycles after sending a byte (counted from
+the begin of the first bit), except, the last byte doesn't trigger IRQ7, and,
+after the 7th byte of the Read command, an additional delay of circa 31000
+cycles occurs before IRQ7 gets triggered (that strange extra delay occurs only
+on original Sony cards, not on cards from other manufacturers).
+There seems to be no extra delays in the Write command, as it seems, the data
+is written on the fly, and one doesn't need to do any write-busy handling...
+although, theoretically, the write shouldn't start until verifying the
+checksum... so it can't be done on the fly at all...?
+
+Notes
+Responses in brackets are don't care, (00h) means usually zero, (pre) means
+usually equal to the previous command byte (eg. the response to LSB is MSB).
+
+Memory cards are reportedly "Flash RAM" which sounds like bullshit, might be
+battery backed SRAM, or FRAM, or slower EEPROM or FLASH ROM, or vary from card
+to card...?
+
+Memory Card Data Format
+-----------------------
+
+Data Size
+ Total Memory 128KB = 131072 bytes = 20000h bytes
+ 1 Block 8KB = 8192 bytes = 2000h bytes
+ 1 Frame 128 bytes = 80h bytes
+The memory is split into 16 blocks (of 8 Kbytes each), and each block is split
+into 64 sectors (of 128 bytes each). The first block is used as Directory, the
+remaining 15 blocks are containing Files, each file can occupy one or more
+blocks.
+
+Header Frame (Block 0, Frame 0)
+ 00h-01h Memory Card ID (ASCII "MC")
+ 02h-7Eh Unused (zero)
+ 7Fh Checksum (all above bytes XORed with each other) (usually 0Eh)
+
+Directory Frames (Block 0, Frame 1..15)
+ 00h-03h Block Allocation State
+ 00000051h - In use ;first-or-only block of a file
+ 00000052h - In use ;middle block of a file (if 3 or more blocks)
+ 00000053h - In use ;last block of a file (if 2 or more blocks)
+ 000000A0h - Free ;freshly formatted
+ 000000A1h - Free ;deleted (first-or-only block of file)
+ 000000A2h - Free ;deleted (middle block of file)
+ 000000A3h - Free ;deleted (last block of file)
+ 04h-07h Filesize in bytes (2000h..1E000h; in multiples of 8Kbytes)
+ 08h-09h Pointer to the NEXT block number (minus 1) used by the file
+ (ie. 0..14 for Block Number 1..15) (or FFFFh if last-or-only block)
+ 0Ah-1Eh Filename in ASCII, terminated by 00h (max 20 chars, plus ending 00h)
+ 1Fh Zero (unused)
+ 20h-7Eh Garbage (usually 00h-filled)
+ 7Fh Checksum (all above bytes XORed with each other)
+Filesize [04h..07h] and Filename [0Ah..1Eh] are stored only in the first
+directory entry of a file (ie. with State=51h or A1h), other directory entries
+have that bytes zero-filled.
+
+Filename Notes
+The first some letters of the filename should indicate the game to which the
+file belongs, in case of commercial games this is conventionally done like so:
+Two character region code:
+ "BI"=Japan, "BE"=Europe, "BA"=America
+followed by 10 character game code,
+ in "AAAA-NNNNN" form ;for Pocketstation executables replace "-" by "P"
+where the "AAAA" part does imply the region too; (SLPS/SCPS=Japan,
+SLUS/SCUS=America, SLES/SCES=Europe) (SCxS=Made by Sony, SLxS=Licensed by
+Sony), followed by up to 8 characters,
+ "abcdefgh"
+(which may identify the file if the game uses multiple files; this part often
+contains a random string which seems to be allowed to contain any chars in
+range of 20h..7Fh, of course it shouldn't contain "?" and "*" wildcards).
+
+Broken Sector List (Block 0, Frame 16..35)
+ 00h-03h Broken Sector Number (Block*64+Frame) (FFFFFFFFh=None)
+ 04h-7Eh Garbage (usually 00h-filled) (some cards have [08h..09h]=FFFFh)
+ 7Fh Checksum (all above bytes XORed with each other)
+If Block0/Frame(16+N) indicates that a given sector is broken, then the data
+for that sector is stored in Block0/Frame(36+N).
+
+Broken Sector Replacement Data (Block 0, Frame 36..55)
+ 00h-7Fh Data (usually FFh-filled, if there's no broken sector)
+
+Unused Frames (Block 0, Frame 56..62)
+ 00h-7Fh Unused (usually FFh-filled)
+
+Write Test Frame (Block 0, Frame 63)
+Reportedly "write test". Usually same as Block 0 ("MC", 253 zero-bytes, plus
+checksum 0Eh).
+
+Title Frame (Block 1..15, Frame 0) (in first block of file only)
+ 00h-01h ID (ASCII "SC")
+ 02h Icon Display Flag
+ 11h...Icon has 1 frame (static) (same image shown forever)
+ 12h...Icon has 2 frames (animated) (changes every 16 PAL frames)
+ 13h...Icon has 3 frames (animated) (changes every 11 PAL frames)
+ Values other than 11h..13h seem to be treated as corrupted file
+ (causing the file not to be listed in the bootmenu)
+ 03h Block Number (1-15) "icon block count" Uh?
+ (usually 01h or 02h... might be block number within
+ files that occupy 2 or more blocks)
+ (actually, that kind of files seem to HAVE title frames
+ in ALL of their blocks; not only in their FIRST block)
+ (at least SOME seem to have such duplicated title frame,
+ but not all?)
+ 04h-43h Title in Shift-JIS format (64 bytes = max 32 characters)
+ 44h-4Fh Reserved (00h)
+ 50h-5Fh Reserved (00h) ;<-- this region is used for the Pocketstation
+ 60h-7Fh Icon 16 Color Palette Data (each entry is 16bit CLUT)
+For more info on entries [50h..5Fh], see
+--> Pocketstation File Header/Icons
+
+Icon Frame(s) (Block 1..15, Frame 1..3) (in first block of file only)
+ 00h-7Fh Icon Bitmap (16x16 pixels, 4bit color depth)
+Note: The icons are shown in the BIOS bootmenu (which appears when starting the
+PlayStation without a CDROM inserted). The icons are drawn via GP0(2Ch)
+command, ie. as Textured four-point polygon, opaque, with texture-blending,
+whereas the 24bit blending color is 808080h (so it's quite the same as raw
+texture without blending). As semi-transparency is disabled, Palette/CLUT
+values can be 0000h=FullyTransparent, or 8000h=SolidBlack (the icons are
+usually shown on a black background, so it doesn't make much of a difference).
+
+Data Frame(s) (Block 1..15, Frame N..63; N=excluding any Title/Icon Frames)
+ 00h-7Fh Data
+Note: Files that occupy more than one block are having only ONE Title area, and
+only one Icon area (in the first sector(s) of their first block), the
+additional blocks are using sectors 0..63 for plain data.
+
+Shift-JIS Character Set (16bit) (used in Title Frames)
+Can contain japanese or english text, english characters are encoded like so:
+ 81h,40h --> SPC
+ 81h,43h..97h --> punctuation marks
+ 82h,4Fh..58h --> "0..9"
+ 82h,60h..79h --> "A..Z"
+ 82h,81h..9Ah --> "a..z"
+Titles shorter than 32 characters are padded with 00h-bytes.
+Note: The titles are <usually> in 16bit format (even if they consist of raw
+english text), however, the BIOS memory card manager does also accept 8bit
+characters 20h..7Fh (so, in the 8bit form, the title could be theoretically up
+to 64 characters long, but, nethertheless, the BIOS displays only max 32
+chars).
+For displaying Titles, the BIOS includes a complete Shift-JIS character set,
+--> BIOS Character Sets
+Shift-JIS is focused on asian languages, and does NOT include european letters
+(eg. such with accent marks). Although the non-japanese PSX BIOSes DO include a
+european character set, the BIOS memory card manager DOESN'T seem to translate
+any title character codes to that character set region.
+
+Memory Card Images
+------------------
+
+There are a lot of different ways to get a save from a memory card onto your
+PC's hard disk, and these ways sometimes involve sticking some additional
+information into a header at the beginning of the file.
+
+Raw Memory Card Images (without header) (ie. usually 128K in size)
+ SmartLink .PSM,
+ WinPSM .PS,
+ DataDeck .DDF,
+ FPSX .MCR,
+ ePSXe .MCD...
+don't stick any header on the data at all, so you can just read it in and treat
+it like a raw memory card.
+
+All of these headers contain a signature at the top of the file. The three most
+common formats and their signatures are:
+
+ Connectix Virtual Game Station format (.MEM): "VgsM", 64 bytes
+ PlayStation Magazine format (.PSX): "PSV", 256 bytes
+
+some programs will OMIT any blank or unallocated blocks from the end of the
+memory card -- if only three save blocks on the card are in use, for example,
+saving the other twelve is pointless.
+
+Xploder and Action Replay Files (54 byte header)
+ 00h..14h Filename in ASCII, terminated by 00h (max 20 chars, plus ending 00h)
+ 15h..35h Title in ASCII, terminated by 00h (max 32 chars, plus ending 00h)
+ 36h.. File Block(s) (starting with the Title sector)
+This format contains only a single file (not a whole memory card). The filename
+should be the same as used in the Memory Card Directory. The title is more or
+less don't care; it may be the SHIFT-JIS title from the Title Sector converted
+to ASCII.
+
+Other
+"There exists another single-save format with a 128 byte header containing a
+raw index frame for the initial block, which must be updated to match the
+destination card, and the raw save data. I have seen this format once, but I
+don't remember what it was called or where it came from. You may want to
+account for this possibility in your format detection logic."
+
+.GME Files (usually 20F40h bytes)
+InterAct GME format, produced by the DexDrive.
+ 000h 12 ASCII String "123-456-STD",00h
+ 00Ch 4 Usually zerofilled (or meaningless garbage in some files)
+ 010h 5 Always 00h,00h,01h,00h,01h
+ 015h 16 Copy of Sector 0..15 byte[00h] ;"M", followed by allocation states
+ 025h 16 Copy of Sector 0..15 byte[08h] ;00h, followed by next block values
+ 035h 11 Usually zerofilled (or meaningless garbage in some files)
+ 040h F00h Fifteen Description Strings (each one 100h bytes, padded with 00h)
+ F40h 128K Memory Card Image (128K) (unused sectors 00h or FFh filled)
+This is a very strange file format, no idea where it comes from. It contains a
+F40h bytes header (mainly zerofilled), followed by the whole 128K of FLASH
+memory (mainly zerofilled, too, since it usually contains only a small single
+executable file).
+
+Memory Card Notes
+-----------------
+
+Sony PSX Memory Cards
+Sony has manufactured only 128KByte memory cards for PSX, no bigger/smaller
+ones.
+
+Sony PS2 Memory Cards
+A special case would be PS2 cards, these are bigger, but PS2 cards won't fit
+into PSX cards slots (unless when cutting an extra notch in the card edge
+connector), a PSX game played on a PS2 console could theoretically access PS2
+cards (if it supports the different directory structure on that cards).
+
+Third Party Cards with bigger capacity
+Some third party cards contain larger memory chips, however, the PSX
+games/kernel are supporting only regular 128Kbyte cards, so the extra memory
+can be used only by dividing it into several 128Kbyte memory card images.
+Selecting a different memory card image can be done by a switch or button on
+the card, or via joypad key combinations (joypad/card are sharing the same
+signals, so the card could watch the traffic on joypad bus, provided that the
+MIPS CPU is actually reading the joypad).
+
+Third Party Cards with bigger capacity and Data Compression
+Some cards are additionally using data compression to increase the card
+capacity, but that techinque is having rather bad reputation and could result
+in data loss. For example, if a game has allocated four blocks on the memory
+card, then it'll expect to be able to overwrite that four blocks at any time
+(without needing to handle "memory card full" errors), however, if the card is
+full, and if the newly written data has worse compression ratio, then the card
+will be unable to store the new game position (and may have already overwritten
+parts of the old game position). As a workaround, such cards may use a LED to
+warn users when running low on memory (ideally, there should be always at least
+128Kbytes of free memory).
+
+Joytech Smart Card Adaptor
+The smart card adaptor plugs into memory card slot, and allows to use special
+credit card-shaped memory cards. There don't seem to be any special features,
+ie. the hardware setup does just behave like normal PSX memory cards.
+
+Datel VMEM (virtual memory card storage on expansion port)
+The Datel/Interact VMEM exists as standalone VMEM cartridge, and some Datel
+Cheat Devices do also include the VMEM feature. Either way, the VMEM connects
+to expansion port, and contain some large FLASH memory, for storing multiple
+memory cards on it. Unknown, how that memory is accessed (maybe it must be
+copied to a regular memory card, or maybe they've somehow hooked the Kernel (or
+even the hardware signals?) so that games could directly access the VMEM?
+
+Passwords (instead of Memory Cards)
+Some older games are using passwords instead of memory cards to allow the user
+to continue at certain game positions. That's nice for people without memory
+card, but unfortunately many of that games are restricted to it - it'd be more
+user friendly to support both passwords, and, optionally, memory cards.
+
+Yaroze Access Cards (DTL-H3020)
+The Yaroze Access Card connects to memory card slot, the card resembles regular
+memory cards, but it doesn't contain any storage memory. Instead, it does
+merely support a very basic Access Card detection command:
+ Send Reply Comment
+ 21h N/A? Probably replies HighZ (ie. probably reads FFh)?
+ 53h 0xh? Replies unknown 8bit value (upper 4bit are known to be zero)?
+Ie. when receiving 21h as first byte, it replies by an ACK, and does then
+output 0xh as response to the next byte.
+Without the Access Card, the Yaroze Bootdisc will refuse to work (the disc
+contains software for transferring data to/from PC, for developing homebrew
+games).
+
+Pocketstation (Memory Card with built-in LCD screen and buttons)
+--> Pocketstation
+
+Pocketstation
+-------------
+
+Pocketstation
+--> Pocketstation Overview
+--> Pocketstation I/O Map
+--> Pocketstation Memory Map
+--> Pocketstation IO Video and Audio
+--> Pocketstation IO Interrupts and Buttons
+--> Pocketstation IO Timers and Real-Time Clock
+--> Pocketstation IO Infrared
+--> Pocketstation IO Memory-Control
+--> Pocketstation IO Communication Ports
+--> Pocketstation IO Power Control
+--> Pocketstation SWI Function Summary
+--> Pocketstation SWI Misc Functions
+--> Pocketstation SWI Communication Functions
+--> Pocketstation SWI Execute Functions
+--> Pocketstation SWI Date/Time/Alarm Functions
+--> Pocketstation SWI Flash Functions
+--> Pocketstation SWI Useless Functions
+--> Pocketstation BU Command Summary
+--> Pocketstation BU Standard Memory Card Commands
+--> Pocketstation BU Basic Pocketstation Commands
+--> Pocketstation BU Custom Pocketstation Commands
+--> Pocketstation File Header/Icons
+--> Pocketstation File Images
+--> Pocketstation XBOO Cable
+
+Pocketstation Overview
+----------------------
+
+Sony's Pocketstation (SCPH-4000) (1998)
+The Pocketstation is a memory card with built-in LCD screen and buttons; aside
+from using it as memory storage device, it can be also used as miniature
+handheld console.
+
+ CPU ARM7TDMI (32bit RISC Processor) (variable clock, max 7.995MHz)
+ Memory 2Kbytes SRAM (battery backed), 16Kbytes BIOS ROM, 128Kbytes FLASH
+ Display 32x32 pixel LCD (black and white) (without any grayscales)
+ Sound Mini Speaker "(12bit PCM) x 1 unit" / "8bit PCM with 12bit range"
+ Controls 5 input buttons, plus 1 reset button
+ Infrared Bi-directional (IrDA based)
+ Connector Playstation memory card interface
+ RTC Battery backed Real-Time Clock with time/date function
+ Supply CR2032 Battery (3VDC) (used in handheld mode, and for SRAM/RTC)
+ _________
+ / _______ \
+ | | | |
+ | | LCD | | __
+ | |_______| | Side Views | _|
+ |\_________/| || <-------- Button Cover
+ | O | (Closed) (Open) ||
+ | O O O | ____________ _____|| .------- Reset Button
+ | O | | LCD \____ | | LCD \|__|_
+ |___________| |___________|| |___________| <--- Memory card plug
+
+The RTC Problem
+The main problem of the Pocketstation seems to be that it tends to reset the
+RTC to 1st January 1999 with time 00:00:00 whenever possible.
+The BIOS contains so many RTC-reset functions, RTC-reset buttons, RTC-reset
+flags, RTC-reset communication commands, RTC-reset parameters, RTC-reset
+exceptions, RTC-reset sounds, and RTC-reset animations that it seems as if Sony
+actually WANTED the Time/Date to be destroyed as often as possible.
+The only possible reason for doing this is that the clock hardware is so
+inaccurate that Sony must have decided to "solve" the problem at software
+engineering side, by erasing the RTC values before the user could even notice
+time inaccuracies.
+
+CPU Specs
+For details on the ARM7TDMI CPUs opcodes and exceptions, check GBATEK at,
+http://problemkaputt.de/gbatek.htm (or .txt)
+The GBA uses an ARM7TDMI CPU, too.
+
+Thanks to Exophase, Orion, Fezzik, Dr.Hell for Pocketstation info.
+
+Pocketstation I/O Map
+---------------------
+
+Memory and Memory-Control Registers
+ 00000000h RAM (2KB RAM) (first 512 bytes bytes reserved for kernel)
+ 02000000h FLASH1 Flash ROM (virtual file-mapped addresses in this region)
+ 04000000h BIOS_ROM Kernel and GUI (16KB)
+ 06000000h F_CTRL Control of Flash ROM
+ 06000004h F_STAT Unknown?
+ 06000008h F_BANK_FLG FLASH virtual bank mapping enable flags(16 bits)(R/W)
+ 0600000Ch F_WAIT1 waitstates...?
+ 06000010h F_WAIT2 waitstates, and FLASH-Write-Control-and-Status...?
+ 06000100h F_BANK_VAL FLASH virtual bank mapping addresses (16 words) (R/W)
+ 06000300h F_EXTRA Extra FLASH (256 bytes, including below F_SN, F_CAL)
+ 06000300h F_SN_LO Extra FLASH Serial Number LSBs (nocash: 6BE7h)
+ 06000302h F_SN_HI Extra FLASH Serial Number MSBs (nocash: 426Ch)
+ 06000304h F_? Extra FLASH Unknown ? (nocash: 05CAh)
+ 06000306h F_UNUSED1 Extra FLASH Unused halfword (nocash: FFFFh)
+ 06000308h F_CAL Extra FLASH LCD Calibration (nocash: 001Ah)
+ 0600030Ah F_UNUSED2 Extra FLASH Unused halfword (nocash: FFFFh)
+ 0600030Ch F_? Extra FLASH Unknown ? (nocash: 0010h)
+ 0600030Eh F_UNUSED3 Extra FLASH Unused halfword (nocash: FFFFh)
+ 06000310h F_UNUSED4 Extra FLASH Unused (310..3FFh) (nocash: FFFFh-filled)
+ 08000000h FLASH2 Flash ROM (128KB) (physical addresses in this region)
+ 08002A54h F_KEY1 Flash Unlock Address 1 (W)
+ 080055AAh F_KEY2 Flash Unlock Address 2 (W)
+Interrupts and Timers
+ 0A000000h INT_LATCH Interrupt hold (R)
+ 0A000004h INT_INPUT Interrupt Status (R)
+ 0A000008h INT_MASK_READ Read Interrupt Mask (R)
+ 0A000008h INT_MASK_SET Set Interrupt Mask (W)
+ 0A00000Ch INT_MASK_CLR Clear Interrupt Mask (W)
+ 0A000010h INT_ACK Clear Interrupt hold (W)
+ 0A800000h T0_RELOAD Timer 0 Maximum value
+ 0A800004h T0_COUNT Timer 0 Current value
+ 0A800008h T0_MODE Timer 0 Mode
+ 0A800010h T1_RELOAD Timer 1 Maximum value
+ 0A800014h T1_COUNT Timer 1 Current value
+ 0A800018h T1_MODE Timer 1 Mode
+ 0A800020h T2_RELOAD Timer 2 Maximum value
+ 0A800024h T2_COUNT Timer 2 Current value
+ 0A800028h T2_MODE Timer 2 Mode
+ 0B000000h CLK_MODE Clock control (CPU and Timer Speed) (R/W)
+ 0B000004h CLK_STOP Clock stop (Sleep Mode)
+ 0B800000h RTC_MODE RTC Mode
+ 0B800004h RTC_ADJUST RTC Adjust
+ 0B800008h RTC_TIME RTC Time (R)
+ 0B80000Ch RTC_DATE RTC Date (R)
+Communication Ports, Audio/Video
+ 0C000000h COM_MODE Com Mode
+ 0C000004h COM_STAT1 Com Status Register 1 (Bit1=Error)
+ 0C000008h COM_DATA Com RX Data (R) and TX Data (W)
+ 0C000010h COM_CTRL1 Com Control Register 1
+ 0C000014h COM_STAT2 Com Status Register 2 (Bit0=Ready)
+ 0C000018h COM_CTRL2 Com Control Register 2
+ 0C800000h IRDA_MODE Infrared Control (R/W)
+ 0C800004h IRDA_DATA Infrared TX Data
+ 0C80000Ch IRDA_MISC Infrared Unknown/Reserved
+ 0D000000h LCD_MODE Video Control (R/W)
+ 0D000004h LCD_CAL Video Calibration (?)
+ 0D000100h LCD_VRAM Video RAM (80h bytes; 32x32bit) (R/W)
+ 0D800000h IOP_CTRL IOP control
+ 0D800004h IOP_STAT Read Current Start/Stop bits? (R)
+ 0D800004h IOP_STOP Stop bits? (W)
+ 0D800008h IOP_START Start bits? (W)
+ 0D80000Ch IOP_DATA IOP data? (not used by bios)
+ 0D800010h DAC_CTRL DAC Control (R/W)
+ 0D800014h DAC_DATA DAC data
+ 0D800020h BATT_CTRL Battery Monitor Control
+BIOS and FLASH can be read only in 16bit and 32bit units (not 8bit).
+Upon reset, BIOS ROM is mirrored to address 00000000h (instead of RAM).
+For most I/O ports, it is unknown if they are (R), (W), or (R/W)...?
+I/O ports are usually accessed at 32bit width, occassionally some ports are
+(alternately) accessed at 16bit width. A special case are the F_SN registers
+which seem to be required to be accessed at 16bit (not 32bit).
+
+Memory Access Time
+Memory Access Time for Opcode Fetch:
+ WRAM 1 cycle (for ARM and THUMB)
+ FLASH 2 cycles (for ARM), or 1 cycle (for THUMB)
+ BIOS ?
+Memory Access Time for Data Read/Write:
+ WRAM (and some F_xxx ports) 1 cycle
+ VIRT/PHYS/XTRA_FLASH, BIOS, VRAM, I/O 2 cycles
+For data access, it doesn't matter if the access is 8bit/16bit/32bit (unlike as
+for opcode fetch, where 16bit/thumb can be faster than 32bit/arm). There seems
+to be no timing differences for sequential/non-sequential access.
+Additional memory waitstates can be added via F_WAIT2 (and F_WAIT1 maybe).
+
+Invalid/Unused Memory Locations
+ 00000800h-00FFFFFFh Mirrors of 00000000h-000007FFh (2K RAM)
+ 01000000h-01FFFFFFh Invalid (read causes data abort) (unused 16MB area)
+ 020xxxxxh-0201FFFFh Invalid (read causes data abort) (disabled FLASH banks)
+ 02020000h-02FFFFFFh Invalid (read causes data abort) (no Virt FLASH mirrors)
+ 03000000h-03FFFFFFh Invalid (read causes data abort) (unused 16MB area)
+ 04004000h-04FFFFFFh Mirrors of 04000000h-04003FFFh (16K BIOS)
+ 05000000h-05FFFFFFh Invalid (read causes data abort)
+ 06000014h-060000FFh Zerofilled (or maybe mirror of a ZERO port?) (F_xxx)
+ 06000140h-060002FFh Zerofilled (or maybe mirror of a ZERO port?) (F_xxx)
+ 06000400h-06FFFFFFh Zerofilled (or maybe mirror of a ZERO port?) (F_xxx)
+ 07000000h-07FFFFFFh Invalid (read causes data abort) (unused 16MB area)
+ 08020000h-08FFFFFFh Mirrors of 08000000h-0801FFFFh (128K Physical FLASH)
+ 09000000h-09FFFFFFh Invalid (read causes data abort) (unused 16MB area)
+ 0A000014h-0A7FFFFFh Mirrors of 0A000008h-0A00000Bh (INT_MASK_READ) (I_xxx)
+ 0A80000Ch Mirror of 0A800000h-0A800003h (T0_RELOAD) (T0_xxx)
+ 0A80001Ch Mirror of 0A800000h-0A800003h (T0_RELOAD) (T1_xxx)
+ 0A80002Ch Mirror of 0A800000h-0A800003h (T0_RELOAD) (T2_xxx)
+ 0A800030h-0AFFFFFFh Mirrors of 0A800000h-0A800003h (T0_RELOAD) (T_xxx)
+ 0B000008h-0B7FFFFFh Mirrors of .... ? (CLK_xxx)
+ 0B800010h-0BFFFFFFh Mirrors of 0B800008h-0B80000Bh (RTC_TIME)
+ 0C00000Ch-0C00000Fh Zero (COM_xxx)
+ 0C00001Ch-0C7FFFFFh Zerofilled (or maybe mirror of a ZERO port?) (COM_xxx)
+ 0C800008h-0CFFFFFFh ? (IRDA_xxx)
+ 0D000008h-0D0000FFh Zerofilled (or maybe mirror of a ZERO port?) (LCD_xxx)
+ 0D000180h-0D7FFFFFh Zerofilled (or maybe mirror of a ZERO port?) (LCD_xxx)
+ 0D800018h ? (DAC_xxx)
+ 0D80001Ch ? (DAC_xxx)
+ 0D800024h-0DFFFFFFh Zerofilled (or maybe mirror of a ZERO port?) (BATT_xxx)
+ 0E000000h-FFFFFFFFh Invalid (read causes data abort) (unused 3872MB area)
+
+Unsupported 8bit Reads
+ 02000000h-0201FFFFh VIRT_FLASH ;\
+ 04000000h-04FFFFFFh BIOS_ROM ; "garbage_byte" (see below)
+ 06000300h-060003FFh EXTRA_FLASH ;
+ 08000000h-08FFFFFFh PHYS_FLASH ;/
+ 0A800001h-0AFFFFFFh Timer area, odd addresses (with A0=1) mirror to 0A800001h
+ 0B800001h-0BFFFFFFh RTC area, odd addresses (with A0=1) mirror to ...?
+
+Unsupported 16bit Reads
+ 0B800002h-0BFFFFFEh RTC area, odd addresses (with A1=1) mirror to 0B80000Ah
+
+garbage_byte (for unsupported 8bit reads)
+The "garbage_byte" depends on the LSBs of the read address, prefetched opcodes,
+and recent data fetches:
+ garbage_word = (prefetch OR (ramdata AND FFFFFFD0h))
+ garbage_byte = (garbage_word shr (8*(addr and 3))) AND FFh
+For ARM code, the "prefetch" is the 2nd next opcode after the LDRB:
+ prefetch.bit0-31 = [curr_arm_opcode_addr+8] ;-eg. from arm LDRB
+For THUMB code, the "prefetch" is the 2nd next opcode after the LDRB (no matter
+if that opcode is word-aligned or not), combined with the most recent ARM
+opcode prefetch (eg. from the BX opcode switched from ARM to THUMB mode; that
+value may get changed on interrupts):
+ prefetch.bit0-15 = [recent_arm_opcode_addr+8] ;-eg. from arm BX to thumb
+ prefetch.bit16-31 = [curr_thumb_opcode_addr+4] ;-eg. from thumb LDRB
+The "ramdata" is related to most recent RAM read (eg. from POP or LDR opcodes
+that have read data from RAM; however, writes to RAM, or literal pool reads
+from FLASH don't affect it):
+ ramdata.bit0-31 = [recent_ram_read_addr] ;-eg. from LDR/POP from RAM
+There might be some more/unknown things that affect the garbage (eg. opcode
+fetches from RAM instead of FLASH, partial 8bit/16bit data reads from RAM, or
+reads from I/O areas, current CPU clock speed, or unpredictable things like
+temperature).
+Note: The garbage_byte is "used" by the pocketstation "Rockman" series games.
+
+Pocketstation Memory Map
+------------------------
+
+Overall Memory Map
+ 00000000h RAM RAM (2K) (or mirror of BIOS ROM upon reset)
+ 02000000h FLASH1 Flash ROM (virtual file-mapped addresses in this region)
+ 04000000h BIOS_ROM BIOS (16K) (Kernel and GUI)
+ 06000300h F_SN... Seems to contain a bunch of additional FLASH bytes?
+ 08000000h FLASH2 Flash ROM (128K) (physical addresses in this region)
+ 0D000100h LCD_VRAM Video RAM (128 bytes) (32x32 pixels, 1bit per pixel)
+
+00000000h..000001FFh - Kernel RAM
+The first 200h bytes of RAM are reserved for the kernel.
+ 0000000h 20h Exception handler opcodes (filled with LDR R15,[$+20h] opcodes)
+ 0000020h 20h Exception handler addresses (in ARM state, no THUMB bit here)
+ 0000040h 80h Sector buffer (and BU command parameter work space)
+ 00000C0h 8 ComFlags (see GetPtrToComFlags(), SWI 06h for details)
+ 00000C8h 2 BU Command FUNC3 Address (see GetPtrToFunc3addr() aka SWI 17h)
+ 00000CAh 1 Value from BU Command_50h, reset by SWI 05h (sense_auto_com)
+ 00000CBh 2 Not used
+ 00000CDh 1 Old Year (BCD, 00h..99h) (for sensing wrapping to new century)
+ 00000CEh 1 Alternate dir_index (when [0D0h]=0) (see SWI 15h and SWI 16h)
+ 00000CFh 1 Current Century (BCD, 00h..99h) (see GetBcdDate() aka SWI 0Dh)
+ 00000D0h 2 Current dir_index (for currently executed file, or 0=GUI)
+ 00000D2h 2 New dir_index (PrepareExecute(flag,dir_index,param), SWI 08h)
+ 00000D4h 4 New param (PrepareExecute(flag,dir_index,param), SWI 08h)
+ 00000D8h 8 Alarm Setting (see GetPtrToAlarmSetting() aka SWI 13h)
+ 00000E0h 4 Pointer to SWI table (see GetPtrToPtrToSwiTable() aka SWI 14h)
+ 00000E4h 3x4 Memory Card BU Command variables
+ 00000F0h 1 Memory Card FLAG byte (bit3=new_card, bit2=write_error)
+ 00000F1h 1 Memory Card Error offhold (0=none, 1=once)
+ 00000F2h 6 Not used
+ 00000F8h 4x4 Callback Addresses (set via SetCallbacks(index,proc), SWI 01h)
+ 0000108h 4 Snapshot ID (0xh,00h,"SE")
+ 000010Ch 74h IRQ and SWI stack (stacktop at 180h)
+ 0000180h 80h FIQ stack (stacktop at 200h)
+Although one can modify that memory, one usually shouldn't do that, or at least
+one must backup and restore the old values before returning control to the GUI
+or to other executables. Otherwise, the only way to restore the original values
+would be to press the Reset button (which would erase the RTC time/date).
+
+00000200h..000007FFh - User RAM and User stack (stacktop at 800h)
+This region can be freely used by the game. The memory is zerofilled when the
+game starts.
+
+02000000h - FLASH1 - Flash ROM (virtual file-mapped addresses in this region)
+This region usually contains the currently selected file (including its title
+and icon sectors), used to execute the file in this region, mapped to continous
+addresses at 2000000h and up.
+
+08000000h - FLASH2 - Flash ROM (128K) (physical addresses in this region)
+This region is used by the BIOS when reading the memory card directory (and
+when writing data to the FLASH memory). The banking granularity is 2000h bytes
+(one memory card block), that means that the hardware cannot map Replacement
+Sectors which may be specified in the for Broken Sector List.
+
+04000000h - BIOS ROM (16K) - Kernel and GUI
+ 4000000h 1E00h Begin of Kernel (usually 1E00h bytes)
+ 4000014h 4 BCD Date in YYYYMMDDh format (19981023h for ALL versions)
+ 4001DFCh 4 Core Kernel Version (usually "C061" or "C110")
+ 4001E00h 2200h Begin of GUI (usually 2200h bytes)
+ 4003FFCh 4 Japanese GUI Version (usually "J061" or "J110")
+The "110" version does contain some patches, but does preserve same function
+addresses as the "061" version, still it'd be no good to expect the BIOS to
+contain any code/data at fixed locations (except maybe the GUI version string).
+Kernel functions can be accessed via SWI Opcodes, and, from the PSX-side, via
+BU Commands.
+
+Bus-Width Restrictions
+FLASH and BIOS ROM seem to be allowed to be read only in 16bit and 32bit units,
+not in 8bit units? Similar restrictions might apply for some I/O ports...? RAM
+can be freely read/written in 8bit, 16bit, and 32bit units.
+
+Waitstates
+Unknown if and how many waitstates are applied to the different memory regions.
+The F_WAIT1 and F_WAIT2 registers seem to be somehow waitstate related. FLASH
+memory does probably have a 16bit bus, so 32bit data/opcode fetches might be
+slower then 16bit reads...? Similar delays might happen for other memory and
+I/O regions...?
+
+Pocketstation IO Video and Audio
+--------------------------------
+
+0D000000h - LCD_MODE - LCD control word (R/W)
+ 0-2 Draw mode; seems to turn off bits of the screen;
+ 0: All 32 rows on ;\
+ 1: First 8 rows on ;
+ 2: Second 8 rows on ;
+ 3: Third 8 rows on ; (these are not necessarily all correct?)
+ 4: Fourth 8 rows on ;
+ 5: First 16 rows on ;
+ 6: Middle 16 rows on ;
+ 7: Bottom 16 rows on ;/
+ 3 CPEN (0=Does some weird fade out of the screen, 1=Normal)
+ 4-5 Refresh rate
+ 0: Makes a single blue (yes, blue, yes, on a black/white display)
+ line appear at the top or middle of the screen - don't use!
+ 1: 64Hz? (might be 32Hz too, like 2)
+ 2: 32Hz
+ 3: 16Hz (results in less intensity on black pixels)
+ 6 Display active (0=Off, 1=On)
+ 7 Rotate display by 180 degrees (0=For Handheld Mode, 1=For Docked Mode)
+ 8-31 Unknown (should be zero)
+Software should usually set LCD_MODE.7 equal to INT_INPUT.Bit11 (docking flag).
+In handheld mode, the button-side is facing towards the player, whilst in
+Docked mode (when the Pocketstation is inserted into the PSX controller port),
+the button-side is facing towards the PSX, so the screen coordinates become
+vice-versa, which can be "undone" by the Rotation flag.
+
+0D000004h - LCD_CAL - LCD Calibration (maybe contrast or so?)
+Upon the reset, the kernel sets LCD_CAL = F_CAL AND 0000003Fh. Aside from that,
+it doesn't use LCD_CAL.
+
+0D000100h..D00017Fh - LCD_VRAM - 32x32 pixels, 1bit color depth (R/W)
+This region consists of 32 words (32bit values),
+ [D000100h]=Top, through [D00017Ch]=Bottom-most scanline
+The separate scanlines consist of 32bit each,
+ Bit0=Left, through Bit31=Right-most Pixel (0=White, 1=Black)
+That [D000100h].Bit0=Upper-left arrangement applies if the Rotate bit in
+LCD_MODE.7 is set up in the conventional way, if it is set the opposite way,
+then it becomes [D00017Ch].Bit31=Upper-left.
+The LCD_VRAM area is reportedly mirrored to whatever locations?
+
+0D800010h - DAC_CTRL - Audio Control (R/W)
+ 0 Audio Enable enable (0=Off, 1=On)
+ 1-31 Unknown, usually zero
+Note: Aside from the bit in DAC_CTRL, audio must be also enabled/disabled via
+IOP_STOP/IOP_START bit5. Unknown if/which different purposes that bits have.
+
+0D800014h - DAC_DATA - Audio D/A Converter
+Unknown how many bits are passed to the D/A converter, probably bit8-15, ie. 8
+bits...?
+ 0-7 Probably unused, usually zero (or fractional part when lowered volume)
+ 8-15 Signed Audio Outut Level (usually -7Fh..+7Fh) (probably -80h works too)
+ 16-31 Probably unused, usually sign-expanded from bit15
+The Pocketstation doesn't have any square wave or noise generator (nor a sound
+DMA channel). So the output levels must be written to DAC_DATA by software,
+this is usually done via Timer1/IRQ-8 (to reduce CPU load caused by high audio
+frequencies, it may be much more recommended to use Timer2/FIQ-13, because the
+FIQ handler doesn't need to push r8-r12).
+For example, to produce a 1kHz square wave, the register must be toggled
+high/low at 2kHz rate. If desired, multiple channels can be mixed by software.
+High frequencies and multiple voices may require high CPU speed settings, and
+thus increase battery consumption (aside from that, battery consumption is
+probably increased anyways when the speaker is enabled).
+
+Pocketstation IO Interrupts and Buttons
+---------------------------------------
+
+0A000004h - INT_INPUT - Raw Interrupt Signal Levels (R)
+ Bit Type Meaning
+ 0 IRQ Button Fire (0=Released, 1=Pressed)
+ 1 IRQ Button Right (0=Released, 1=Pressed)
+ 2 IRQ Button Left (0=Released, 1=Pressed)
+ 3 IRQ Button Down (0=Released, 1=Pressed)
+ 4 IRQ Button Up (0=Released, 1=Pressed)
+ 5 ? Unknown? (?)
+ 6 FIQ (!) COM ;for the COM_registers? (via /SEL Pin?)
+ 7 IRQ Timer 0
+ 8 IRQ Timer 1
+ 9 IRQ RTC (square wave) (usually 1Hz) (when RTC paused: 4096Hz)
+ 10 IRQ Battery Low (0=Normal, 1=Battery Low)
+ 11 IRQ Docked ("IOP") (0=Undocked, 1=Docked to PSX) (via VCC Pin?)
+ 12 IRQ Infrared Rx
+ 13 FIQ (!) Timer 2
+ 14-15 N/A Not used
+The buttons are usually read directly from this register (rather than being
+configured to trigger IRQs) (except in Sleep mode, where the Fire Button IRQ is
+usually used to wakeup). Also, bit9-11 are often read from this register.
+The direction keys seem to be separate buttons, ie. unlike as on a joystick or
+DPAD, Left/Right (and Up/Down) can be simultaneously pressed...?
+
+0A000008h - INT_MASK_SET - Set Interrupt Mask (W)
+0A00000Ch - INT_MASK_CLR - Clear Interrupt Mask (W)
+0A000008h - INT_MASK_READ - Read Interrupt Mask (R)
+ INT_MASK_SET Enable Interrupt Flags (0=No change, 1=Enable) (W)
+ INT_MASK_CLR Disable Interrupt Flags (0=No change, 1=Disable) (W)
+ INT_MASK_READ Current Interrupt Enable Flags (0=Disabled, 1=Enabled) (R)
+The locations of the separate bits are same as in INT_INPUT (see there).
+
+0A000000h - INT_LATCH - Interrupt Request Flags (R)
+0A000010h - INT_ACK - Acknowledge Interrupts (W)
+ INT_LATCH Latched Interrupt Requests (0=None, 1=Interrupt Request) (R)
+ INT_ACK Clear Interrupt Requests (0=No change, 1=Acknowledge) (W)
+The locations of the separate bits are same as in INT_INPUT (see there).
+The interrupts seem to be edge-triggered (?), ie. when the corresponding bits
+in INT_INPUT change from 0-to-1. Unknown if the request bits get set when the
+corresponding interrupt is disabled in INT_MASK...?
+
+ATTENTION: The GUI doesn't acknowledge Fire Button interrupts on wakeup... so,
+it seems as if button interrupts are NOT latched... ie. the button "INT_LATCH"
+bits seem to be just an unlatched mirror of the "INT_INPUT" bits... that might
+also apply for some other interrupt...?
+However, after wakeup, the gui does DISABLE the Fire Button interrupt, MAYBE
+that does automatically acknowledge it... in that case it might be latched...?
+
+Reading outside the readable region (that is where exactly?) seems to mirror to
+0A000008h. Enabling IRQs for the buttons seems to make it impossible to poll
+them... is that really true?
+
+Pocketstation IO Timers and Real-Time Clock
+-------------------------------------------
+
+Timer and RTC interrupts
+ INT_INPUT.7 Timer 0 IRQ ;used as 30Hz frame rate IRQ by GUI
+ INT_INPUT.8 Timer 1 IRQ ;used as Audio square wave IRQ by GUI
+ INT_INPUT.13 Timer 2 FIQ (this one via FIQ vector, not IRQ vector)
+ INT_INPUT.9 RTC IRQ (usually 1Hz) (or 4096Hz when RTC paused)
+
+0A800000h - T0_RELOAD - Timer 0 Reload Value
+0A800010h - T1_RELOAD - Timer 1 Reload Value
+0A800020h - T2_RELOAD - Timer 2 Reload Value
+ 0-15 Reload Value (when timer becomes less than zero)
+Writes to this register are ignored if the timer isn't stopped?
+
+0A800004h - T0_COUNT - Timer 0 Current value
+0A800014h - T1_COUNT - Timer 1 Current value
+0A800024h - T2_COUNT - Timer 2 Current value
+ 0-15 Current value (decrementing)
+Timer interrupts: The timers will automatically raise interrupts if they're
+enabled, there's no need to set a bit anywhere for IRQs (but you need to enable
+the respect interrupts in INT_MASK).
+
+0A800008h - T0_MODE - Timer 0 Control
+0A800018h - T1_MODE - Timer 1 Control
+0A800028h - T2_MODE - Timer 2 Control
+ 0-1 Timer Divider (0=Div2, 1=Div32, 2=Div512, 3=Div2 too)
+ 2 Timer Enable (0=Stop, 1=Decrement)
+ 3-15 Unknown (should be zero)
+Timers are clocked by the System Clock (usually 4MHz, when CLK_MODE=7), divided
+by the above divider setting. Note that the System Clock changes when changing
+the CPU speed via CLK_MODE, so Timer Divider and/or Timer Reload must be
+adjusted accordingly.
+
+0B800000h - RTC_MODE - RTC control word
+ 0 Pause RTC (0=Run/1Hz, 1=Pause/4096Hz)
+ 1-3 Select value to be modified via RTC_ADJUST
+ 4-31 Not used?
+The selection bits can be:
+ 00h = Second ;\
+ 01h = Minute ;
+ 02h = Hour ; used in combination with RTC_ADJUST
+ 03h = Day of Week ; while RTC is paused
+ 04h = Day ;
+ 05h = Month ;
+ 06h = Year ;/
+ 07h = Unknown ;-usually used when RTC isn't paused
+When paused, the RTC IRQ bit in INT_INPUT.9 runs at 4096Hz (instead 1Hz).
+
+0B800004h - RTC_ADJUST - Modify value (write only)
+Writing a value here seems to increment the current selected parameter (by the
+RTC control). What is perhaps (?) clear is that you have to wait for the RTC
+interrupt signal to go low before writing to this.
+
+0B800008h - RTC_TIME - Real-Time Clock Time (read only) (R)
+ 0-7 Seconds (00h..59h, BCD)
+ 8-15 Minutes (00h..59h, BCD)
+ 16-23 Hours (00h..23h, BCD)
+ 24-31 Day of week (1=Sunday, ..., 7=Saturday)
+Reading RTC_TIME seems to be somewhat unstable: the BIOS uses a read/retry
+loop, until it has read twice the same value (although it does read the whole
+32bit at once by a LDR opcode, the data is maybe passed through a 8bit or 16bit
+bus; so the LSBs might be a few clock cycles older than the MSBs...?).
+
+0B80000Ch - RTC_DATE - Real-Time Clock Date (read only) (R)
+ 0-7 Day (01h..31h, BCD)
+ 8-11 Month (01h..12h, BCD)
+ 16-23 Year (00h..99h, BCD)
+ 24-31 Unknown? (this is NOT used as century)
+Reading RTC_DATE seems to require the same read/retry method as RTC_TIME (see
+there). Note: The century is stored in battery-backed RAM (in the reserved
+kernel RAM region) rather than in the RTC_DATE register. The whole date,
+including century, can be read via SWI 0Dh, GetBcdDate().
+
+Pocketstation IO Infrared
+-------------------------
+
+The BIOS doesn't contain any IR functions (aside from doing some basic
+initialization and power-down stuff).
+IR is used in Final Fantasy 8's Chocobo World (press Left/Right in the Map
+screen to go to the IR menu), and in Metal Gear Solid Integral (Press Up in the
+main screen), and in PDA Remote 1 & 2 (one-directional TV remote control).
+
+0C800000h - IRDA_MODE - Controlling the protocol - send/recv, etc. (R/W)
+ 0 Transfer Direction (0=Receive, 1=Transmit)
+ 1 Disable IRDA (0=Enable, 1=Disable)
+ 2 Unknown (reportedly IR_SEND_READY, uh?)
+ 3 Unknown (reportedly IR_RECV_READY, uh?)
+ 4-31 Unknown (should be zero)
+
+0C800004h - IRDA_DATA - Infrared TX Data
+ 0 Transmit Data in Send Direction (0=LED Off, 1=LED On)
+ 1-31 Unknown (should be zero)
+Bits are usually encoded as long or short ON pulses, separated by short OFF
+pulses. Where long is usually twice as long as short.
+
+0C80000Ch - IRDA_MISC
+Unknown? Reportedly reserved.
+
+INT_INPUT.12 - IRQ - Infrared RX Interrupt
+Seems to get triggered on raising or falling (?) edges of incoming data. The
+interrupt handler seems to read the current counter value from one of the
+timers (usually Timer 2, with reload=FFFFh) to determine the length of the
+incoming IR pulse.
+
+IR Notes
+Mind that IR hardware usually adopts itself to the normal light conditions, so
+if it receives an IR signal for a longer period, then it may treat that as the
+normal light conditions (ie. as "OFF" state). To avoid that, one would usually
+send a group of ON-OFF-ON-OFF pulses, instead of sending a single long ON
+pulse:
+ ___------------------___ One HIGH bit send as SINGLE-LONG-ON pulse (BAD)
+ ___-_-_-_-_-_-_-_-_-____ One HIGH bit send as MULTIPLE-ON-OFF pulses (OK)
+that might be maybe done automatically by the hardware...?
+
+Reportedly, Bit4 of Port 0D80000Ch (IOP_DATA) is also somewhat IR related...?
+
+Pocketstation IO Memory-Control
+-------------------------------
+
+06000000h - F_CTRL
+ 0-31 Unknown
+Written values are:
+ 00000000h Used when disabling all virtual flash banks
+ 00000001h Used before setting new virtual bank values
+ 00000002h Used after setting virtual bank enable bits
+ 03h Replace ROM at 00000000h by RAM (used after reset)
+The GUI does additionally read from this register (and gets itself trapped in a
+bizarre endless loop if bit0 was zero). Unknown if it's possible to re-enable
+ROM at location 00000000h by writing any other values to this register?
+
+06000004h F_STAT
+ 0-31 Unknown
+The kernel issues a dummy read from this address (before setting F_CTRL to
+00000001h).
+
+06000008h F_BANK_FLG ;FLASH virtual bank mapping enable flags (16 bits)(R/W)
+ 0-15 Enable physical banks 0..15 in virtual region (0=Disable, 1=Enable)
+ 16-31 Unknown (should be zero)
+
+06000100h F_BANK_VAL ;FLASH virtual bank mapping addresses (16 words)(R/W)
+This region contains 16 words, the first word at 06000100h for physical bank 0,
+the last word at 0600013Ch for physical bank 15. Each word is:
+ 0-3 Virtual bank number
+ 4-31 Should be 0
+Unused physical banks are usually mapped to 0Fh (and are additionally disabled
+in the F_BANK_FLG register).
+
+0600000Ch F_WAIT1 ;waitstates...?
+ 0..3 Unknown/not tested
+ 4 hangs hardware? but that bit is used in some cases!
+ 5..31 Unknown/not tested
+Unknown, seems to control some kind of memory waitstates for FLASH (or maybe
+RAM or BIOS ROM). Normally it is set to the following values:
+ F_WAIT1=00000000h when CPU Speed = 00h..07h
+ F_WAIT1=00000010h when CPU Speed = 08h..0Fh
+Note: The kernels Docking/Undocking IRQ-11 handler does additionally do this:
+"F_WAIT1=max(08h,(CLK_MODE AND 0Fh))" (that is a bug, what it actually wants to
+do is to READ the current F_WAIT.Bit4 setting).
+
+06000010h F_WAIT2 ;waitstates, and FLASH-Write-Control-and-Status...?
+ 0 no effect? but that bit is used in some cases! maybe write-enable?
+ 1 hangs hardware?
+ 2 no effect? READ: indicates 0=write-busy, 1=ready? (R)
+ 3 hangs hardware?
+ 4 makes FLASH slower?
+ 5 makes WRAM and F_xxx as slow as other memory (0=1 cycle, 1=2 cycles)
+ 6 hangs hardware? but that bit is used in some cases!
+ 7 no effect?
+ 8..31 Unknown/not tested
+Unknown, seems to control some kind of memory waitstates, maybe for another
+memory region than F_WAIT1, or maybe F_WAIT2 is for writing, and F_WAIT1 for
+reading or so. Normally it is set to the following values:
+ F_WAIT2=00000000h when CPU Speed = 00h..07h ;\same as F_WAIT1
+ F_WAIT2=00000010h when CPU Speed = 08h..0Fh ;/
+In SWI 0Fh and SWI 10h it is also set to:
+ F_WAIT2=00000021h ;SWI 10h, FlashWritePhysical(sector,src)
+ F_WAIT2=00000041h ;SWI 0Fh, FlashWriteSerial(serial_number)
+Before completion, those SWIs do additionally,
+ wait until reading returns F_WAIT2.Bit2 = 1
+ and then set F_WAIT2=00000000h
+
+08002A54h - F_KEY1 - Flash Unlock Address 1 (W)
+080055AAh - F_KEY2 - Flash Unlock Address 2 (W)
+Unlocks FLASH memory for writing. The complete flowchart for writing sector
+data (or header values) is:
+ if write_sector ;\
+ F_WAIT2=00000021h ; write enable or so
+ if write_header ;
+ F_WAIT2=00000041h ;/
+ [80055AAh]=FFAAh ;\
+ [8002A54h]=FF55h ; unlock flash
+ [80055AAh]=FFA0h ;/
+ if write_sector ;\
+ for i=0 to 3Fh ;
+ [8000000h+sector*80h+i*2]=src[i*2] ; write data
+ if write_header ;
+ [8000000h]=new F_SN_LO value ;
+ [8000002h]=new F_SN_HI value ;
+ [8000008h]=new F_CAL value ;/
+ first, wait 4000 clock cycles ;\wait
+ then, wait until F_WAIT2.Bit2=1 ;/
+ F_WAIT2=00000000h ;-write disable or so
+During the write operation one can (probably?) not read data (nor opcodes) from
+FLASH memory, so the above code must be executed either in RAM, or in BIOS ROM
+(see SWI 03h, SWI 0Fh, SWI 10h).
+
+06000300h - F_SN_LO - Serial Number LSBs
+06000302h - F_SN_HI - Serial Number MSBs
+06000308h - F_CAL - Calibration value for LCD
+ 0-15 Data
+This seems to be an additional "header" region of the FLASH memory
+(additionally to the 128K of data). The F_SN registers contain a serial number
+or so (purpose unknown, maybe intended as some kind of an "IP" address for more
+complex infrared network applications), the two LO/HI registers must be read by
+separate 16bit LDRH opcodes (not by a single 32bit LDR opcode). The F_CAL
+register contains a 6bit calibration value for LCD_CAL (contrast or so?).
+Although only the above 3 halfwords are used by the BIOS, the "header" is
+unlike to be 6 bytes in size, probably there are whatever number of additional
+"header" locations at 06000300h and up...?
+Note: Metal Gear Solid Integral uses F_SN as some kind of copy protection (the
+game refuses to run and displays "No copy" if F_SN is different as when the
+pocketstation file was initially created).
+
+F_BANK_VAL and F_BANK_FLG Notes
+Observe that the physical_bank number (p) is used as array index, and that the
+virtual bank number (v) is stored in that location, ie. table[p]=v, which is
+unlike as one may have expected it (eg. on a 80386 CPU it'd be vice-versa:
+table[v]=p).
+Due to the table[p]=v assignment, a physical block cannot be mirrored to
+multiple virtual blocks, instead, multiple physical blocks can be mapped to the
+same virtual block (unknown what happens in that case, maybe the data becomes
+ANDed together).
+
+Pocketstation IO Communication Ports
+------------------------------------
+
+0C000000h - COM_MODE - Com Mode
+ 0 Data Output Enable (0=None/HighZ, 1=Output Data Bits)
+ 1 /ACK Output Level (0=None/HighZ, 1=Output LOW)
+ 2 Unknown (should be set when expecting a NEW command...?)
+ 3-31 Unknown (should be zero)
+
+0C000008h - COM_DATA - Com RX/TX Data
+ 0-7 Data (Write: to be transmitted to PSX, Read: been received from PSX)
+ 8-31 Unknown
+
+0C000004h - COM_STAT1 - Com Status Register 1 (Bit1=Error)
+ 0 Unknown
+ 1 Error flag or so (0=Okay, 1=Error)
+ 2-31 Unknown
+Seems to indicate whatever error (maybe /SEL disabled during transfer, or
+timeout, or parity error or something else?) in bit1. Meaning of the other bits
+is unknown. Aside from checking the error flag, the kernel does issue a dummy
+read at the end of each transfer, maybe to acknowledge something, maybe the
+hardware simply resets the error bit after reading (although the kernel doesn't
+handle the bit like so when receiving the 1st command byte).
+Aside from the above error flag, one should check if INT_INPUT.11 becomes zero
+during transfer (which indicates undocking).
+
+0C000014h - COM_STAT2 - Com Status Register 2 (Bit0=Ready)
+ 0 Ready flag (0=Busy, 1=Ready) (when 8bits have been transferred)
+ 1-31 Unknown
+
+0C000010h - COM_CTRL1 - Com Control Register 1
+ 0 Unknown (should be set AT BEGIN OF A NEW command...?)
+ 1 Unknown (0=Disable something, 1=Enable something)
+ 2-31 Unknown (should be zero)
+Used values are:
+ 00000000h = unknown? disable
+ 00000002h = unknown? enable
+ 00000003h = unknown? at BEGIN of a new command
+When doing the enable thing, Bit1 should be set to 0-then-1...? Bit0 might
+enable the data shift register... and bit1 might be a master enable and master
+acknowledge for the COM interrupt... or something else?
+
+0C000018h - COM_CTRL2 - Com Control Register 2
+ 0 Unknown (should be set, probably starts or acknowledges something)
+ 1 Unknown (should be set when expecting a NEW command...?)
+ 2-31 Unknown (should be zero)
+Used values are:
+ 00000001h = unknown? used before AND after each byte-transfer
+ 00000003h = unknown? used after LAST byte of command (and when init/reset)
+Maybe that two bits acknowledge the ready/error bits?
+
+INT_INPUT.6 FIQ (!) COM for the COM_registers? (via /SEL Pin?)
+ (via FIQ vector, not IRQ vector)
+
+INT_INPUT.11 IRQ Docked ("IOP") (0=Undocked, 1=Docked to PSX)
+Probably senses the voltage on the cartridge slots VCC Pin. Becomes zero when
+Undocked (and probably also when the PSX is switched off).
+The Kernel uses IRQ-11 for BOTH sensing docking and undocking, ie. as if the
+IRQ would be triggered on both 0-to-1 and 1-to-0 transistions... though maybe
+that feature just relies on switch-bounce. For the same reason (switch bounce),
+the IRQ-11 handler performs a delay before it checks the new INT_INPUT.11
+setting (ie. the delay skips the unstable switch bound period, and allows the
+signal to stabilize).
+
+IOP_START/IOP_STOP.Bit1
+The BIOS adjusts this bit somehow in relation to communication. Unknown
+when/why/how it must be used. For details on IOP_START/IOP_STOP see Power
+Control chapter.
+
+Opcode E6000010h (The Undefined Instruction) - Write chr(r0) to TTY
+This opcode is used by the SN Systems emulator to write chr(r0) to a TTY style
+text window. r0 can be ASCII characters 20h and up, or 0Ah for CRLF. Using that
+opcode is a not too good idea because the default BIOS undef instruction
+handler simply runs into an endless loop, so games that are using it (eg.
+Break-Thru by Jason) won't work on real hardware. That, unless the game would
+change the undef instruction vector at [04h] in Kernel RAM, either replacing it
+by a MOVS R15,R14 opcode (ignore exception and return to next opcode), or by
+adding exception handling that outputs the character via IR or via whatever
+cable connection. Observe that an uninitialized FUNC3 accidently destroys
+[04h], so first init FUNC3 handler via SWI 17h, before trying to change [04h],
+moreover, mind that SWI 05h may reset FUNC3, causing the problem to reappear.
+Altogether, it'd be MUCH more stable to write TTY characters to an unused I/O
+port... only problem is that it's still unknown which I/O ports are unused...
+ie. which do neither trap data aborts, nor do mirror to existing ports...?
+
+Pocketstation IO Power Control
+------------------------------
+
+0B000000h - CLK_MODE - Clock control (CPU and Timer Speed) (R/W)
+ 0-3 Clock Ratio (01h..08h, see below) (usually 7 = 3.99MHz) (R/W)
+ 4 Clock Change State (0=Busy, 1=Ready) (Read-only)
+ 5-15 ?
+Allows to change the CPU clock (and Timer clock, which is usually one half of
+the CPU clock, or less, depending on the Timer Divider). Possible values are:
+ 00h = hangs hardware ;-don't use
+ 01h = 0.063488 MHz ;\
+ 02h = 0.126976 MHz ;
+ 03h = 0.253952 MHz ; 31*8000h / 1,2,4,8,16
+ 04h = 0.507904 MHz ;
+ 05h = 1.015808 MHz ;/
+ 06h = 1.998848 MHz ;\
+ 07h = 3.997696 MHz ; 61*8000h * 1,2,4
+ 08h = 7.995392 MHz ;/
+ 09h..0Fh = same as 08h ;-aliases
+Before changing CLK_MODE, F_WAIT1 and F_WAIT2 should be adjusted accordingly
+(see there for details). Note that many memory regions have waitstates, the
+full CPU speed can be reached mainly with code/data in WRAM.
+
+0B000004h - CLK_STOP - Clock stop (Sleep Mode)
+Stops the CPU until an interrupt occurs. The pocketstation doesn't have a
+power-switch nor standby button, the closest thing to switch "power off" is to
+enter sleep mode. Software should do that when the user hasn't pressed buttons
+for 1-2 seconds (that, only in handheld mode, not when docked to the PSX; where
+it's using the PSX power supply instead of the battery).
+ 0 Stop Clock (1=Stop)
+ 1-15 ?
+Wakeup is usually done by IRQ-0 (Fire Button) and IRQ-11 (Docking). If alarm is
+enabled, then the GUI also enables IRQ-9 (RTC), and compares RTC_TIME against
+the alarm setting each time when it wakes up.
+Before writing to CLK_STOP, one should do:
+ DAC_CTRL=0 ;\disable sound
+ IOP_STOP=20h ;/
+ LCD_MODE=0 ;-disable video
+ IRDA=whatever ;-disable infrared (if it was used)
+ BATT_CTRL=BATT_CTRL AND FFFFFFFCh ;-do whatever
+ INT_MASK_SET=801h ;-enable Docking/Fire wakeup interrupts
+The GUI uses CLK_STOP only for Standby purposes (not for waiting for its 30Hz
+"frame rate" timer 0 interrupt; maybe that isn't possible, ie. probably
+CLK_STOP does completely disable the system clock, and thus does stop
+Timer0-2...?)
+
+0D800000h - IOP_CTRL - Configures whatever...? (R/W)
+ 0-3 Probably Direction for IOP_DATA bit0..3 (0=Input, 1=Output)
+ 4-31 Unknown/Unused (seems to be always zero)
+Unknown. Set to 0000000Fh by BIOS upon reset. Aside from that, the BIOS does
+never use that register.
+
+0D800004h - IOP_STAT (R) - Read Current bits? -- No, seems to be always 0
+0D800004h - IOP_STOP (W) - Set IOP_DATA Bits
+0D800008h - IOP_START (W) - Clear IOP_DATA Bits
+These two ports are probably accessing a single register, writing "1" bits to
+IOP_STOP sets bits in that register, and writing "1" bits to IOP_START clears
+bits... or vice-versa...? Writing "0" bits to either port seems to leave that
+bits unchanged. The meaning of most bits is still unknown:
+ 0 Unknown, STARTED by Kernel upon reset
+ 1 Red LED, Communication related (START=Whatever, STOP=Whatelse) (?)
+ 2 Unknown, STARTED by Kernel upon reset
+ 3 Unknown, STARTED by Kernel upon reset
+ 4 Never STARTED nor STOPPED by BIOS (maybe an INPUT, read via IOP_DATA)
+ 5 Sound Enable (START=On, STOP=Off)
+ 6 Unknown, STOPPED by Kernel upon reset
+ 7-31 Unknown, never STARTED nor STOPPED by BIOS
+Aside from Bit1, it's probably not neccessary to change the unknown bits...?
+Sound is usually disabled by setting IOP_STOP=00000020h. IOP_STAT is rarely
+used. Although, one piece of code in the BIOS disables sound by setting
+IOP_STOP=IOP_STAT OR 00000020h, that is probably nonsense, probably intended to
+keep bits stopped if they are already stopped (which would happen anyways),
+however, the strange code implies that reading from 0D800004h returns the
+current status of the register, and that the bits in that register seem to be
+0=Started, and 1=Stopped...?
+
+0D80000Ch - IOP_DATA (R)
+ 0 ?
+ 1 Red LED (0=On, 1=Off)
+ 2 ?
+ 3 ?
+ 4 Seems to be always 1 (maybe Infrared input?)
+ 5-31 Unknown/Unused (seems to be always zero)
+Unknown. Not used by the BIOS. Reportedly this register is 0010h if IR
+Connection...? This register is read by Rewrite ID, and by Harvest Moon. Maybe
+bit4 doesn't mean <if> IR connection exist, but rather <contains> the received
+IR data level...?
+
+0D800020h - BATT_CTRL - Battery Monitor Control?
+Unknown. Somehow battery saving related. Upon reset, and upon leaving sleep
+mode, the BIOS does set BATT_CTRL=00000000h. Before entering sleep mode, it
+does set BATT_CTRL=BATT_CTRL AND FFFFFFFCh, whereas, assuming that BATT_CTRL
+was 00000000h, ANDing it with FFFFFFFCh would simply leave it unchanged...
+unless the hardware (or maybe a game) sets some bits in BATT_CTRL to nonzero
+values...?
+
+Battery Low Interrupt
+ INT_INPUT.10 IRQ Battery Low (0=Normal, 1=Battery Low)
+Can be used to sense if the battery is low, if so, one may disable sound output
+and/or reduce the CPU speed to increase the remaining battery lifetime. Unknown
+how long the battery lasts, and how much the lifetime is affected by audio,
+video, infrared, cpu speed, and sleep mode...?
+The pocketstation can be also powered through the VCC pin (ie. when docked to
+the PSX, then it's working even if the battery is empty; or even without
+battery).
+
+Pocketstation SWI Function Summary
+----------------------------------
+
+SWI Function Summary
+BIOS functions can be called via SWI opcodes (from both ARM and THUMB mode) (in
+ARM mode, the SWI function number is in the lower 8bit of the 24bit field;
+unlike as for example on the GBA, where it'd be in the upper 8bit). Parameters
+(if any) are passed in r0,r1,r2. Return value is stored in r0 (all other
+registers are left unchanged).
+ SWI 00h - Reset() ;don't use out: everything destroyed
+ SWI 01h - SetCallbacks(index,proc) out: old proc
+ SWI 02h - CustomSwi2(r0..r6,r8..r10) out: r0
+ SWI 03h - FlashWriteVirtual(sector,src) out: 0=okay, 1=failed
+ SWI 04h - SetCpuSpeed(speed) out: old_speed
+ SWI 05h - SenseAutoCom() out: garbage
+ SWI 06h - GetPtrToComFlags() out: ptr (usually 0C0h)
+ SWI 07h - ChangeAutoDocking(flags.16-18) out: incoming flags AND 70000h
+ SWI 08h - PrepareExecute(flag,dir_index,param) out: dir_index (new or old)
+ SWI 09h - DoExecute(snapshot_saving_flag) out: r0=r0 (failed) or r0=param
+ SWI 0Ah - FlashReadSerial() out: F_SN
+ SWI 0Bh - ClearComFlagsBit10() out: new [ComFlags] (with bit10=0)
+ SWI 0Ch - SetBcdDateTime(date,time) out: garbage (RTC_DATE/10000h)
+ SWI 0Dh - GetBcdDate() out: date (with century in MSBs)
+ SWI 0Eh - GetBcdTime() out: time and day-of-week
+ SWI 0Fh - FlashWriteSerial(serial_number) out: garbage (r0=0) ;old BIOS only!
+ SWI 10h - FlashWritePhysical(sector,src) out: 0=okay, 1=failed
+ SWI 11h - SetComOnOff(flag) out: garbage retadr to swi handler
+ SWI 12h - TestSnapshot(dir_index) out: 0=normal, 1=MCX1 with 1,0,"SE"
+ SWI 13h - GetPtrToAlarmSetting() out: ptr to alarm_setting
+ SWI 14h - GetPtrToPtrToSwiTable() out: ptr-to-ptr to swi_table
+ SWI 15h - MakeAlternateDirIndex(flag,dir_index) out: alt_dir_index (new/old)
+ SWI 16h - GetDirIndex() out: dir_index (or alternate)
+ SWI 17h - GetPtrToFunc3addr() out: ptr to func3 address
+ SWI 18h - FlashReadWhateverByte(sector) out: [8000000h+sector*80h+7Eh]
+ SWI 19h..FFh - garbage
+ SWI 100h..FFFFFFh - mirrors of SWI 00h..FFh
+The BIOS uses the same memory region for SWI and IRQ stacks, so both may not
+occur simultaneously, otherwise one stack would be destroyed by the other
+(normally that is no problem; IRQs are automatically disabled by the CPU during
+SWI execution, SWIs aren't used from inside of default IRQ handlers, and SWIs
+shouldn't be used from inside of hooked IRQ handlers).
+
+Pocketstation SWI Misc Functions
+--------------------------------
+
+SWI 01h - SetCallbacks(index,proc)
+ r0=0 Set SWI 02h callback (r1=proc, or r1=0=reset/default)
+ r0=1 Set IRQ callback (r1=proc, or r1=0=none/default)
+ r0=2 Set FIQ callback (r1=proc, or r1=0=none/default)
+ r0=3 Set Download Notification callback (r1=proc, or r1=0=bugged/default)
+All callbacks are called via BX opcodes (ie. proc.bit0 can be set for THUMB
+code). SetCallbacks returns the old proc value (usually zero). The callbacks
+are automatically reset to zero when (re-)starting an executable, or when
+returning control to the GUI, so there's no need to restore the values by
+software.
+
+IRQ and FIQ Callbacks
+Registers r0,r1,r12 are pushed by the kernels FIQ/IRQ handlers (so the
+callbacks can use that registers without needing to push them). The FIQ handler
+can additionally use r8..r11 without pushing them (the CPU uses a separate set
+of r8..r12 registers in FIQ mode, nethertheless, the kernel DOES push r12 in
+FIQ mode, without reason). Available stack is 70h bytes for the FIQ callback,
+and 64h bytes for the IRQ callback.
+The callbacks don't receive any incoming parameters, and don't need to respond
+with a return value. The callback should return to the FIQ/IRQ handler (via
+normal BX r14) (ie. it should not try to return to User mode).
+The kernel IRQ handler does (after the IRQ callback) process IRQ-11 (IOP)
+(which does mainly handle docking/undocking), and IRQ-9 (RTC) (which increments
+the century if the year wrapped from 99h to 00h).
+And the kernel FIQ handler does (before the FIQ callback) process IRQ-6 (COM)
+(which does, if ComFlags.Bit9 is set, handle bu_cmd's) (both IRQs and FIQs are
+disabled, and the main program is stopped until the bu_cmd finishes, or until a
+joypad command is identified irrelevant, among others that means that
+sound/timer IRQs aren't processed during that time, so audio output may become
+distorted when docked).
+When docked, the FIQ callback should consist of only a handful of opcodes, eg.
+it may contain a simple noise, square wave generator, or software based sound
+"DMA" function, but it should not contain more time-consuming code like sound
+envelope processing; otherwise IRQ-6 (COM) cannot be executed fast enough to
+handle incoming commands.
+
+SWI 02h - CustomSwi2(r0..r6,r8..r10) out: r0
+Calls the SWI2 callback function (which can be set via SWI 01h). The default
+callback address is 00000000h (so, by default, it behaves identically as SWI
+00h). Any parameters can be passed in r0..r6 and r8..r10 (the other registers
+aren't passed to the callback function). Return value can be stored in r0 (all
+other registers are pushed/popped by the swi handler, as usually). Available
+space on the swi stack is 38h bytes.
+SWI2 can be useful to execute code in privileged mode (eg. to initialize FIQ
+registers r8..r12 for a FIQ based sound engine) (which usually isn't possible
+because the main program runs in non-privileged user mode).
+
+SWI 04h - SetCpuSpeed(speed) out: old_speed
+Changes the CPU speed. The BIOS uses it with values in range 01h..07h. Unknown
+if value 00h can be also used? The function also handles values bigger than
+07h, of which, some pieces of BIOS code look as if 08h would be the maximum
+value...?
+Before setting the new speed, the function sets F_WAIT1 and F_WAIT2 to
+00000000h (or to 00000010h if speed.bit3=1). After changing the speed (by
+writing the parameter to CLK_MODE) it does wait until the new speed is applied
+(by waiting for CLK_MODE.bit4 to become zero). The function returns the old
+value of CLK_MODE, anded with 0Fh.
+
+Pocketstation SWI Communication Functions
+-----------------------------------------
+
+Communication (aka BU Commands, received from the PSX via the memory card slot)
+can be handled by the pocketstations kernel even while a game is running.
+However, communications are initially disabled when starting a game, so the
+game should enable them via SWI 11h, and/or via calling SWI 05h once per frame.
+
+SWI 11h - SetComOnOff(flag)
+Can be used to enable/disable communication. When starting an executable,
+communication is initially disabled, so it'd be a good idea to enable them
+(otherwise the PSX cannot communicate with the Pocketstation while the game is
+running).
+When flag=0, disables communication: Intializes the COM_registers, disables
+IRQ-6 (COM), and clears ComFlags.9. When flag=1, enables communication:
+Intializes the COM_registers, enables IRQ-6 (COM), sets ComFlags.9 (when
+docked), or clears Sys.Flags.9 (when undocked), and sets FAST cpu_speed=7 (only
+when docked). The function returns garbage (r0=retadr to swi_handler).
+
+SWI 06h - GetPtrToComFlags()
+Returns a pointer to the ComFlags word in RAM, which contains several
+communication related flags (which are either modified upon docking/undocking,
+or upon receiving certain bu_cmd's). The ComFlags word consists of the
+following bits:
+ 0-3 Whatever (set/cleared when docked/undocked, and modified by bu_cmd's)
+ 4-7 Not used (should be zero)
+ 8 IRQ-11 (IOP) occurred (set by irq handler, checked/cleared by SWI 05h)
+ 9 Communication Enabled And Docked (0=No, 1=Yes; prevents DoExecute)
+ 10 Reject writes to Broken Sector Region (sector 16..55) (0=No, 1=Yes)
+ 11 Start file request (set by bu_cmd_59h, processed by GUI, not by Kernel)
+ 12-15 Not used (should be zero)
+ 16 Automatically power-down DAC audio on insert/removal (0=No, 1=Yes)
+ 17 Automatically power-down IRDA infrared on insert/removal (0=No, 1=Yes)
+ 18 Automatically adjust LCD screen rotate on insert/removal (0=No, 1=Yes)
+ 19-27 Not used (should be zero)
+ 28 Indicates if a standard bu_cmd (52h/53h/57h) was received (0=No, 1=Yes)
+ 29 Set date/time request (set by bu_cmd FUNC0, processed by BIOS)
+ 30 Destroy RTC and Start GUI request (set by bu_cmd_59h, dir_index=FFFEh)
+ 31 Not used (should be zero)
+Bit16-18 can be changed via SWI 07h, ChangeAutoDocking(flags). Bit10 can be
+cleared by SWI 0Bh, ClearComFlagsBit10().
+
+SWI 07h - ChangeAutoDocking(flags.16-18)
+ 0-15 Not used (should be zero)
+ 16 Automatically power-down DAC audio on insert/removal (0=No, 1=Yes)
+ 17 Automatically power-down IRDA infrared on insert/removal (0=No, 1=Yes)
+ 18 Automatically adjust LCD screen rotate on insert/removal (0=No, 1=Yes)
+ 19-31 Not used (should be zero)
+Copies bit16-18 of the incoming parameter to ComFlags.16-18, specifying how the
+kernel IRQ-11 (IOP) handler shall process docking/undocking from the PSX
+cartridge slot. The function returns the incoming flags value ANDed with
+70000h.
+
+SWI 0Bh - ClearComFlagsBit10()
+Resets ComFlags.Bit10, ie. enables bu_cmd_57h (write_sector) to write to the
+Broken Sector region in FLASH memory (sector 16..55). SWI 0Bh returns the
+current ComFlags value (the new value, with bit10=0).
+Aside from calling SWI 0Bh, ComFlags.10 is also automatically cleared upon
+IRQ-10 (IOP) (docking/undocking). ComFlags.10 can get set/cleared by the
+Download Notification callback.
+
+SWI 05h - SenseAutoCom()
+Checks if docking/undocking has occurred (by examining ComFlags.8, which gets
+set by the kernel IRQ-11 (IOP) handler). If that flag was set, then the
+function does reset it, and does then reset FUNC3=0000h and [0CAh]=00h (both
+only if docked, not when undocked), and, no matter if docked or undocked, it
+enables communication; equivalent to SetComOnOff(1); which sets/clears
+ComFlags.9. The function returns garbage (r0=whatever).
+The GUI is calling SWI 05h once per frame. The overall purpose is unknown. It's
+a good idea to reset FUNC3 and to Enable Communication (although that'd be
+required only when docked, not when undocked), but SWI 05h is doing that only
+on (un-)docking transitions (not when it was already docked). In general, it'd
+make more sense to do proper initializations via SWI 11h and SWI 17h as than
+trusting SWI 05h to do the job. The only possibly useful effect is that SWI 05h
+does set/clear ComFlags.9 when docked/undocked.
+
+SWI 17h - GetPtrToFunc3addr()
+Returns a pointer to a halfword in RAM which contains the FUNC3 address (for
+bu_cmd_5bh and bu_cmd_5ch). The address is only 16bit, originated at 02000000h
+in FLASH (ie. it can be only in the first 64K of the file), bit0 can be set for
+THUMB code. The default address is zero, which behaves bugged: It accidently
+sets [00000004h]=00000000h, ie. replaces the Undefined Instruction exception
+vector by a "andeq r0,r0,r0" opcode, due to that NOP-like opcode, any Undefined
+Instruction exceptions will run into the SWI vector at [00000008h], and
+randomly execute an SWI function; with some bad luck that may execute one of
+the FlashWrite functions and destroy the saved files.
+Although setting 0000h acts bugged, one should restore that setting before
+returning control to GUI or other executables; otherwise the address would
+still point to the FUNC3 address of the old unloaded executable, which is worse
+than the bugged effect.
+The FUNC3 address is automatically reset to 0000h when (if) SWI 05h
+(SenseAutoCom) senses new docking.
+
+Download Notification callback
+Can be used to mute sound during communication, see SWI 01h,
+SetCallbacks(index,proc), and BU Command 5Dh for details.
+
+Pocketstation SWI Execute Functions
+-----------------------------------
+
+SWI 08h - PrepareExecute(flag,dir_index,param)
+dir_index should be 0=GUI, or 1..15=First block of game. When calling
+DoExecute, param is passed to the entrypoint of the game or GUI in r0 register
+(see notes on GUI <param> values belows). For games, param may be interpreted
+in whatever way.
+When flag=0, the function simply returns the old dir_index value. When flag=1,
+the new dir_index and param values are stored in Kernel RAM (for being used by
+DoExecute); the values are stored only if dir_index=0 (GUI), or if dir_index
+belongs to a file with "SC" and "MCX0" or "MCX1" IDs in it's title sector. If
+dir_index was accepted, then the new dir_index value is returned, otherwise the
+old dir_index is returned.
+
+GUI <param> values - for PrepareExecute(1,0,param)
+PrepareExecute(1,0,param) prepares to execute the GUI (rather than a file).
+When executing the GUI, <param> consists of the following destructive bits:
+ 0-7 Command number (see below, MSBs=Primary command, LSBs=another dir_index)
+ 8 Do not store Alarm setting in Kernel RAM (0=Normal, 1=Don't store)
+ 9-31 Not used (should be zero)
+The command numbers can be:
+ Command 0xh --> Erase RTC time/date
+ Command 1xh --> Enter GUI Time Screen with speaker symbol
+ Command 20h --> Enter GUI Time Screen with alarm symbol
+ Command 2xh --> Prompt for new Date/Time, then start dir_index (x)
+ Command 3xh --> Enter GUI File Selection Screen, with dir_index (x) selected
+ Command xxh --> Erase RTC time/date (same as Command 0xh)
+For Command 2xh and 3xh, the lower 4bit of the command (x) must be a valid
+dir_index of the 1st block of a pocketstation executable, otherwise the BIOS
+erases the RTC time/date. Bit8 is just a "funny" nag feature, allowing the user
+to change the alarm setting, but with the changes being ignored (bit8 can be
+actually useful in BU Command 59h, after FUNC2 was used for changing alarm).
+
+SWI 09h - DoExecute(), or DoExecute(snapshot_saving_flag) for MCX1
+Allows to return control to the GUI (when dir_index=0), or to start an
+executable (when dir_index=1..15). Prior to calling DoExecute, parameters
+should be set via PrepareExecute(1,dir_index,param), when not doing that,
+DoExecute would simply restart the current executable (which may be a desired
+effect in some cases).
+The "snapshot_saving_flag" can be ommited for normal (MCX0) files, that
+parameter is used only for special (MCX1) files (see Snapshot Notes for
+details).
+Caution: DoExecute fails (and returns r0=unchanged) when ComFlags.9=1 (which
+indicates that communications are enabled, and that the Pocketstation is
+believed to be docked to the PSX). ComFlags.9 can be forcefully cleared by
+calling SetComOnOff(0), or it can be updated according to the current
+docking-state by calling SetComOnOff(1) or SenseAutoCom().
+
+SWI 16h - GetDirIndex()
+Returns the dir_index for the currently executed file. If that value is zero,
+ie. if there is no file executed, ie. if the function is called by the GUI,
+then it does instead return the "alternate" dir_index (as set via SWI 15h).
+
+SWI 15h - MakeAlternateDirIndex(flag,dir_index) out: alt_dir_index (new/old)
+Applies the specified dir_index as "alternate" dir_index (for being retrieved
+via SWI 16h for whatever purpose). The dir_index is applied only when flag=1,
+and only if dir_index is 0=none, or if it is equal to the dir_index of the
+currently executed file (ie. attempts to make other files being the "alternate"
+one are rejected). If successful, the new dir_index is returned, otherwise the
+old dir_index is returned (eg. if flag=0, or if the index was rejected).
+
+SWI 12h - TestSnapshot(dir_index)
+Tests if the specified file contains a load-able snapshot, ie. if it does have
+the "SC" and "MCX1" IDs in the title sector, and the 01h,00h,"SE" ID in the
+snapshot header. If so, it returns r0=1, and otherwise returns r0=0.
+
+Snapshot Notes (MCX1 Files)
+Snapshots are somewhat automatically loaded/saved when calling DoExecute:
+If the old file (the currently executed file) contains "SC" AND "MCX1" IDs in
+the title sector, then the User Mode CPU registers and User RAM at 200h..7FFh
+are automatically saved in the files snapshot region in FLASH memory, with the
+snapshot_saving_flag being applied as bit0 of the 0xh,00h,"SE" ID of the
+snapshot header).
+If the new file (specified in dir_index) contains load-able snapshot data (ie.
+if it has "SC" and "MCX1" IDs in title sector, and 01h,00h,"SE" ID in the
+snapshot region), then the BIOS starts the saved snapshot data (instead of
+restarting the executable at its entrypoint). Not too sure if that feature is
+really working... the snapshot loader seems to load User RAM from the wrong
+sectors... and it seems to jump directly to User Mode return address... without
+removing registers that are still stored on SWI stack... causing the SWI stack
+to underflow after loading one or two snapshots...?
+
+Pocketstation SWI Date/Time/Alarm Functions
+-------------------------------------------
+
+SWI 0Ch - SetBcdDateTime(date,time)
+Sets the time and date, the parameters are having the same format as SWI 0Dh
+and SWI 0Eh return values (see there). The SWI 0Ch return value contains only
+garbage (r0=RTC_DATE/10000h).
+
+SWI 0Dh - GetBcdDate()
+ 0-7 Day (01h..31h, BCD)
+ 8-11 Month (01h..12h, BCD)
+ 16-31 Year (0000h..9999h, BCD)
+Returns the current date, the lower 24bit are read from RTC_DATE, the century
+in upper 8bit is read from Kernel RAM.
+
+SWI 0Eh - GetBcdTime()
+ 0-7 Seconds (00h..59h, BCD)
+ 8-15 Minutes (00h..59h, BCD)
+ 16-23 Hours (00h..23h, BCD)
+ 24-31 Day of week (1=Sunday, ..., 7=Saturday)
+Returns the current time and day of week, read from RTC_TIME.
+
+SWI 13h - GetPtrToAlarmSetting()
+Returns a pointer to a 64bit value in Kernel RAM, the upper word (Bit32-63)
+isn't actually used by the BIOS, except that, the bu_cmd FUNC3 does transfer
+the whole 64bits. The meaning of the separate bits is:
+ 0-7 Alarm Minute (00h..59h, BCD)
+ 8-15 Alarm Hour (00h..23h, BCD)
+ 16 Alarm Enable (0=Off, 1=On)
+ 17 Button Lock (0=Normal, 1=Lock) (pressing all 5 buttons in GUI)
+ 18-19 Volume Shift (0=Normal/Loud, 1=Medium/Div4, 2=Mute/Off)
+ 20-22 Not used (should be zero)
+ 23 RTC Initialized (0=Not yet, 1=Yes, was initialized from within GUI)
+ 24-31 Not used (should be zero)
+ 32-63 Pointer to 8x8 BIOS Charset (characters "0"..."9" plus strange symbols)
+The RTC hardware doesn't have a hardware-based alarm feature, instead, the
+alarm values must be compared with the current time by software. Alarm is
+handled only by the GUI portion of the BIOS. The Kernel doesn't do any alarm
+handling, so alarm won't occur while a game is executed (unless the game
+contains code that handles alarm).
+Games are usually using only the lower 16bit of the charset address, ORed with
+04000000h (although the full 32bit is stored in RAM).
+ CHR(00h..09h) = Digits "0..9"
+ CHR(0Ah) = Space " "
+ CHR(0Bh) = Colon ":"
+ CHR(0Ch) = Button Lock (used by Final Fantasy 8's Chocobo World)
+ CHR(0Dh) = Speaker Medium; or loud if followed by chr(0Eh)
+ CHR(0Eh) = Speaker Loud; to be appended to chr(0Dh)
+ CHR(0Fh) = Speaker Off
+ CHR(10h) = Battery Low (used by PocketMuuMuu's Cars)
+ CHR(11h) = Alarm Off
+ CHR(12h) = Alarm On
+ CHR(13h) = Memory Card symbol
+
+Pocketstation SWI Flash Functions
+---------------------------------
+
+SWI 10h - FlashWritePhysical(sector,src)
+Writes 80h-bytes at src to the physical sector number (0..3FFh, originated at
+08000000h), and does then compare the written data with the source data.
+Returns 0=okay, or 1=failed.
+
+SWI 03h - FlashWriteVirtual(sector,src)
+The sector number (0..3FFh) is a virtual sector number (originated at
+02000000h), the function uses the F_BANK_VAL settings to translate it to a
+physical sector number, and does then write the 80h-bytes at src to that
+location (via the FlashWritePhysical function). Returns 0=okay, or 1=failed (if
+the write failed, or if the sector number exceeded the filesize aka the
+virtually mapped memory region).
+
+SWI 0Ah - FlashReadSerial()
+Returns the 32bit value from the two 16bit F_SN registers (see F_SN for
+details).
+
+SWI 0Fh - FlashWriteSerial(serial_number) ;old BIOS only!
+Changes the 32bit F_SN value in the "header" region of the FLASH memory. The
+function also rewrites the F_CAL value (but it simply rewrites the old value,
+so it's left unchanged). The function isn't used by the BIOS, no idea if it is
+used by any games. No return value (always returns r0=0).
+This function is supported by the old "061" version BIOS only (the function is
+padded with jump opcodes which hang the CPU in endless loops on newer "110"
+version).
+
+SWI 18h - FlashReadWhateverByte(sector)
+Returns [8000000h+sector*80h+7Eh] AND 00FFh. Purpose is totally unknown... the
+actual FLASH memory doesn't contain any relevant information at that locations
+(eg. the in the directory sectors, that byte is unused, usually zero)... and,
+reading some kind of status or manufacturer information would first require to
+command the hardware to output that info...?
+
+Pocketstation SWI Useless Functions
+-----------------------------------
+
+SWI 00h - Reset() ;don't use, destroys RTC settings
+Reboots the pocketstation, similar as when pressing the Reset button. Don't
+use! The BIOS bootcode does (without any good reason) reset the RTC registers
+and alarm/century settings in RAM to Time 00:00:00, Date 01 Jan 1999, and Alarm
+00:00 disabled, so, after reset, the user would need to re-enter that values.
+Aside from the annoying destroyed RTC settings, the function is rather
+unstable: it does jump to address 00000000h in RAM, which should usually
+redirect to 04000000h in ROM, however, most pocketstation games are programmed
+in C language, where "pointer" is usually pronounced "pointer?" without much
+understanding of whether/why/how to initialize that "strange things", so
+there's a good probability that one of the recently executed games has
+accidently destroyed the reset vector at [00000000h] in battery-backed RAM.
+
+SWI 14h - GetPtrToPtrToSwiTable()
+Returns a pointer to a word in RAM, which contains another pointer which
+usually points to SWI table in ROM. Changing that word could be (not very)
+useful for setting up a custom SWI table in FLASH or in RAM. When doing that,
+one must restore the original setting before returning control to the GUI or to
+another executable (the setting isn't automatically restored).
+
+Pocketstation BU Command Summary
+--------------------------------
+
+The Pocketstation supports the standard Memory Card commands (Read Sector,
+Write Sector, Get Info), plus a couple of special commands.
+
+BU Command Summary
+ 50h Change a FUNC 03h related value or so
+ 51h N/A
+ 52h Standard Read Sector command
+ 53h Standard Get ID command
+ 54h N/A
+ 55h N/A
+ 56h N/A
+ 57h Standard Write Sector command
+ 58h Get an ID or Version value or so
+ 59h Prepare File Execution with Dir_index, and Parameter
+ 5Ah Get Dir_index, ComFlags, F_SN, Date, and Time
+ 5Bh Execute Function and transfer data from Pocketstation to PSX
+ 5Ch Execute Function and transfer data from PSX to Pocketstation
+ 5Dh Execute Custom Download Notification Function ;via SWI 01h with r0=3
+ 5Eh Get-and-Send ComFlags.bit1,3,2
+ 5Fh Get-and-Send ComFlags.bit0
+Commands 5Bh and 5Ch can use the following functions:
+ FUNC 00h - Get or Set Date/Time
+ FUNC 01h - Get or Set Memory Block
+ FUNC 02h - Get or Set Alarm/Flags
+ FUNC 03h - Custom Function 3 ;via SWI 17h, GetPtrToFunc3addr()
+ FUNC 80h..FFh - Custom Functions 80h..FFh ;via Function Table in File Header
+
+Pocketstation BU Standard Memory Card Commands
+----------------------------------------------
+
+For general info on the three standard memory card commands (52h, 53h, 57h),
+and for info on the FLAG response value, see:
+--> Memory Card Read/Write Commands
+
+BU Command 52h (Read Sector)
+Works much as on normal memory cards, except that, on the Pocketstation, the
+Read Sector command return 00h as dummy values; instead of the "(pre)" dummies
+that occur on normal memory cards.
+The Read Sector command does reproduce the strange delay (that occurs between
+5Ch and 5Dh bytes), similar as on normal original Sony memory cards, maybe
+original cards did (maybe) actually DO something during that delay period, the
+pocketstation BIOS simply blows up time in a wait loop (maybe for compatibility
+with original cards).
+
+BU Command 53h (Get ID)
+The Get ID command (53h) returns exactly the same values as normal original
+Sony memory cards.
+
+BU Command 57h (Write Sector)
+The Write Sector command has two new error codes (additonally to the normal
+47h="G"=Good, 4Eh="N"=BadChecksum, FFh=BadSector responses). The new error
+codes are (see below for details):
+ FDh Reject write to Directory Entries of currently executed file
+ FEh Reject write to write-protected Broken Sector region (sector 16..55)
+And, like Read Sector, it returns 00h instead of "(pre)" as dummy values.
+
+Write Error Code FDh (Directory Entries of currently executed file)
+The FDh error code is intended to prevent the PSX bootmenu (or other PSX games)
+to delete the currently executed file (which would crash the pocketstation -
+once when the deleted region gets overwritten by a new file), because the PSX
+bootmenu and normal PSX games do not recognize the new FDh error code the
+pocketstation does additionally set FLAG.3 (new card), which should be
+understood by all PSX programs.
+The FDh error code occurs only on directory sectors of the file (not on its
+data blocks). However, other PSX games should never modify files that belong to
+other games (so there should be no compatibility problem with other PSX
+programs that aren't aware of the file being containing currently executed
+code).
+However, the game that has created the executable pocketstation file must be
+aware of that situation. If the file is broken into a Pocketstation Executable
+region and a PSX Gameposition region, then it may modify the Gameposition stuff
+even while the Executable is running. If the PSX want to overwrite the
+executable then it must first ensure that it isn't executed (eg. by retrieving
+the dir_index of the currently executed file via BU Command 5Ah, and comparing
+it against the first block number in the files FCB at the PSX side; for file
+handle "fd", the first block is found at "[104h]+fd*2Ch+24h" in PSX memory).
+
+Write Error Code FEh (write-protected Broken Sector region, sector 16..55)
+The write-protection is enabled by ComFlags.bit10 (which can be set/cleared via
+BU Command 5Dh). That bit should be set before writing Pocketstation
+excecutables (the Virtual Memory banking granularity is 2000h bytes, which
+allows to map whole blocks only, but cannot map single sectors, which would be
+required for files with broken sector replacements).
+Unlike Error FDh, this error code doesn't set FLAG.3 for notifying normal PSX
+programs about the error (which is no problem since normally Error FEh should
+never occur since ComFlags.10 is usually zero). For more info on ComFlags.10,
+see SWI 0Bh aka ClearComFlagsBit10(), and BU Command 5Dh.
+
+Pocketstation BU Basic Pocketstation Commands
+---------------------------------------------
+
+BU Command 50h (Change a FUNC 03h related value or so)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 50h FLAG Send Command 50h
+ VAL 00h Send new [0CAh], receive length of following data (00h)
+Might be somehow related to FUNC 03h...?
+
+BU Command 58h (Get an ID or Version value or so)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 58h FLAG Send Command 58h
+ (0) 02h Send dummy/zero, receive length of following data (02h)
+ (0) 01h Send dummy/zero, receive whatever value (01h)
+ (0) 01h Send dummy/zero, receive another value (01h)
+
+BU Command 59h (Prepare File Execution with Dir_index, and Parameter)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 59h FLAG Send Command 59h
+ (0) 06h Send dummy/zero, receive length of following data (06h)
+ NEW OLD Send new dir_index.8-15, receive old dir_index.8-15
+ NEW OLD Send new dir_index.0-7, receive old dir_index.0-7
+ PAR (0) Send exec_parameter.0-7, receive dummy/zero
+ PAR (0) Send exec_parameter.8-15, receive dummy/zero
+ PAR (0) Send exec_parameter.16-23, receive dummy/zero
+ PAR (0) Send exec_parameter.24-31, receive dummy/zero
+The new dir_index can be the following:
+ 0000h..000Fh --> Request to Start GUI or File (with above parameter bits)
+ 0010h..FFFDh --> Not used, acts same as FFFFh (see below)
+ FFFEh --> Request to Destroy RTC and Start GUI (with parameter 00000000h)
+ FFFFh --> Do nothing (transfer all bytes, but don't store the new values)
+Upon dir_index=0000h (Start GUI) or 0001..000Fh (start file), a request flag in
+ComFlags.11 is set, the GUI does handle that request, but the Kernel doesn't
+handle it (so it must be handled in the game; ie. check ComFlags.11 in your
+mainloop, and call DoExecute when that bit is set, there's no need to call
+PrepareExecute, since that was already done by the BU Command).
+Caution: When dir_index=0000h, then <param> should be a value that does NOT
+erase the RTC time/date (eg. 10h or 20h) (most other values do erase the RTC,
+see SWI 08h for details).
+Upon dir_index=FFFEh, a similar request flag is set in ComFlags.30, and, the
+Kernel (not the GUI) does handle that request in its FIQ handler (however, the
+request is: To reset the RTC time/date and to start the GUI with uninitialized
+irq/svc stack pointers, so this unpleasant and bugged feature shouldn't ever be
+used). Finally, dir_index=FFFFh allows to read the current dir_index value
+(which could be also read via BU Command 5Ah).
+
+BU Command 5Ah (Get Dir_index, ComFlags, F_SN, Date, and Time)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 5Ah FLAG Send Command 5Ah
+ (0) 12h Send dummy/zero, receive length of following data (12h)
+ (0) INDX Send dummy/zero, receive curr_dir_index.bit8-15 (00h)
+ (0) INDX Send dummy/zero, receive curr_dir_index.bit0-7 (00h..0Fh)
+ (0) FLG Send dummy/zero, receive ComFlags.bit0 (00h or 01h)
+ (0) FLG Send dummy/zero, receive ComFlags.bit1 (00h or 01h)
+ (0) FLG Send dummy/zero, receive ComFlags.bit3 (00h or 01h)
+ (0) FLG Send dummy/zero, receive ComFlags.bit2 (00h or 01h)
+ (0) SN Send dummy/zero, receive F_SN.bit0-7 (whatever)
+ (0) SN Send dummy/zero, receive F_SN.bit8-15 (whatever)
+ (0) SN Send dummy/zero, receive F_SN.bit16-23 (whatever)
+ (0) SN Send dummy/zero, receive F_SN.bit24-31 (whatever)
+ (0) DATE Send dummy/zero, receive BCD Day (01h..31h)
+ (0) DATE Send dummy/zero, receive BCD Month (01h..12h)
+ (0) DATE Send dummy/zero, receive BCD Year (00h..99h)
+ (0) DATE Send dummy/zero, receive BCD Century (00h..99h)
+ (0) TIME Send dummy/zero, receive BCD Second (00h..59h)
+ (0) TIME Send dummy/zero, receive BCD Minute (00h..59h)
+ (0) TIME Send dummy/zero, receive BCD Hour (00h..23h)
+ (0) TIME Send dummy/zero, receive BCD Day of Week (01h..07h)
+At midnight, the function may accidently return the date for the old day, and
+the time for the new day.
+
+BU Command 5Eh (Get-and-Send ComFlags.bit1,3,2)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 5Eh FLAG Send Command 5Eh
+ (0) 03h Send dummy/zero, receive length of following data (03h)
+ NEW OLD Send new ComFlags.bit1, receive old ComFlags.bit1 (00h or 01h)
+ NEW OLD Send new ComFlags.bit3, receive old ComFlags.bit3 (00h or 01h)
+ NEW OLD Send new ComFlags.bit2, receive old ComFlags.bit2 (00h or 01h)
+
+BU Command 5Fh (Get-and-Send ComFlags.bit0)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 5Fh FLAG Send Command 5Fh
+ (0) 01h Send dummy/zero, receive length of following data (01h)
+ NEW OLD Send new ComFlags.bit0, receive old ComFlags.bit0 (00h or 01h)
+
+Pocketstation BU Custom Pocketstation Commands
+----------------------------------------------
+
+BU Command 5Bh (Execute Function and transfer data from Pocketstation to PSX)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 5Bh FLAG Send Command 5Bh
+ FUNC FFh Send Function Number, receive FFh (indicating variable length)
+ (0) LEN1 Send dummy/zero, receive length of parameters (depending on FUNC)
+ ... (0) Send parameters (LEN1 bytes), and receive dummy/zero
+ <-------- at this point, the function is executed for the first time
+ (0) LEN2 Send dummy/zero, receive length of data (depending on FUNC)
+ (0) ... Send dummy/zero, receive data (LEN2 bytes) from pocketstation
+ (0) FFh Send dummy/zero, receive FFh
+ <-------- at this point, the function is executed for the second time
+See below for more info on the FUNC value and the corresponding functions.
+
+BU Command 5Ch (Execute Function and transfer data from PSX to Pocketstation)
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 5Ch FLAG Send Command 5Ch
+ FUNC FFh Send Function Number, receive FFh (indicating variable length)
+ (0) LEN1 Send dummy/zero, receive length of parameters (depending on FUNC)
+ ... (0) Send parameters (LEN1 bytes), and receive dummy/zero
+ <-------- at this point, the function is executed for the first time
+ (0) LEN2 Send dummy/zero, receive length of data (depending on FUNC)
+ ... (0) Send data (LEN2 bytes) to pocketstation, receive dummy/zero
+ (0) FFh Send dummy/zero, receive FFh
+ <-------- at this point, the function is executed for the second time
+See below for more info on the FUNC value and the corresponding functions.
+
+BU Command 5Dh (Execute Custom Download Notification Function)
+Can be used to notify the GUI (or games that do support this function) about
+following "download" operations (or uploads or other BU commands).
+BU commands are handled inside of the kernels FIQ handler, that means both IRQs
+and FIQs are disabled during a BU command transmission, so any IRQ or FIQ based
+audio frequency generators will freeze during BU commands. To avoid distorted
+noise, it's best to disable sound for the duration specified in bit0-7. If the
+PSX finishes before the originally specified duration has expired, then it can
+resend this command with bit8=1 to notify the pocketstation that the "download"
+has completed.
+ Send Reply Comment
+ 81h N/A Memory Card Access
+ 5Dh FLAG Send Command 5Dh
+ (0) 03h Send dummy/zero, receive length of following data (03h)
+ VAL (0) Send receive value.16-23 (whatever), receive dummy/zero
+ VAL (0) Send receive value.8-15 (download flags), receive dummy/zero
+ VAL (0) Send receive value.0-7 (download duration), receive dummy/zero
+The Download Notification callback address can be set via SWI 01h,
+SetCallbacks(3,proc), see there for details. At kernel side, the function
+execution is like so:
+ If value.8-15 = 00h, then ComFlags.bit10=1, else ComFlags.bit10=0.
+ If download_callback<>0 then call download_callback with r0=value.0-23.
+In the GUI, the bu_cmd_5dh_hook/callback handles parameter bits as so (and
+games should probably handle that bits in the same fashion, too):
+ bit0-7 download duration (in whatever units... 30Hz, RTC, seconds...?)
+ bit8 download finished (0=no, 1=yes, cancel any old/busy duration)
+ bit9-23 not used by gui
+If PSX games send any of the standard commands (52h,53h,57h) to access the
+memory card without using command 5Dh, then GUI automatically sets the duration
+to 01h (and pauses sound only for that short duration).
+
+FUNC 00h - Get or Set Date/Time (FUNC0)
+LEN1 is 00h (no parameters), and LEN2 is 08h (eight data bytes):
+ DATE Get or Send BCD Day (01h..31h)
+ DATE Get or Send BCD Month (01h..12h)
+ DATE Get or Send BCD Year (00h..99h)
+ DATE Get or Send BCD Century (00h..99h)
+ TIME Get or Send BCD Second (00h..59h)
+ TIME Get or Send BCD Minute (00h..59h)
+ TIME Get or Send BCD Hour (00h..23h)
+ TIME Get or Send BCD Day of Week (01h..07h)
+At midnight, the function may accidently return the date for the old day, and
+the time for the new day.
+
+FUNC 01h - Get or Set Memory Block (FUNC1)
+LEN1 is 05h (five parameters bytes):
+ ADDR Send Pocketstation Memory Address.bit0-7
+ ADDR Send Pocketstation Memory Address.bit8-15
+ ADDR Send Pocketstation Memory Address.bit16-23
+ ADDR Send Pocketstation Memory Address.bit24-31
+ LEN2 Send Desired Data Length (00h..80h, automatically clipped to max=80h)
+LEN2 is variable (using the 5th byte of the above parameters):
+ ... Get or Send LEN2 Data byte(s), max 80h bytes
+Can be used to write to RAM (and eventually also to I/O ports; when you know
+what you are doing). In the read direction it can read almost anything: RAM,
+BIOS ROM, I/O Ports, Physical and Virtual FLASH memory. Of which, trying to
+read unmapped Virtual FLASH does probably (?) cause a Data Abort exception (and
+crash the Pocketstation), so that region may be read only if a file is loaded
+(check that dir_index isn't zero, via BU Command 5Ah, and, take care not to
+exceed the filesize of that file).
+BUG: When sending more than 2 data bytes in the PSX-to-Pocketstation direction,
+then ADDR must be word-aligned (the BIOS tries to handle odd destination
+addresses, but when doing that, it messes up the alignment of another internal
+pointer).
+
+FUNC 02h - Get or Set Alarm/Flags (FUNC2)
+LEN1 is 00h (no parameters), and LEN2 is 08h (eight data bytes):
+ DATA Get or Send Alarm.bit0-7, Alarm Minute (00h..59h, BCD)
+ DATA Get or Send Alarm.bit8-15, Alarm Hour (00h..23h, BCD)
+ DATA Get or Send Alarm.bit16-23, Flags, see SWI 13h, GetPtrToAlarmSetting()
+ DATA Get or Send Alarm.bit24-31, Not used (usually 00h)
+ DATA Get or Send Alarm.bit32-39, BIOS Charset Address.0-7
+ DATA Get or Send Alarm.bit40-47, BIOS Charset Address.8-15
+ DATA Get or Send Alarm.bit48-55, BIOS Charset Address.16-23
+ DATA Get or Send Alarm.bit56-63, BIOS Charset Address.24-31
+Changing the alarm value while the GUI is running works only with some
+trickery: For a sinister reason, the GUI copies the alarm setting to User RAM
+when it gets started, that copy isn't affected by FUNC2, so the GUI believes
+that the old alarm setting does still apply (and writes that old values back to
+Kernel RAM when leaving the GUI). The only workaround is:
+Test if the GUI is running, if so, restart it via Command 59h (with
+dir_index=0, and param=0120h or similar, ie. with param.bit8 set), then execute
+FUNC2, then restart the GUI again (this time with param.bit8 zero).
+
+FUNC 03h - Custom Function 3 (aka FUNC3)
+LEN1 is 04h (fixed) (four parameters bytes):
+ VAL Send Parameter Value.bit0-7
+ VAL Send Parameter Value.bit8-15
+ VAL Send Parameter Value.bit16-23
+ VAL Send Parameter Value.bit24-31
+LEN2 is variable (depends on the return value of the 1st function call):
+ ... Get or Send LEN2 Data byte(s)
+The function address can be set via SWI 17h, GetPtrToFunc3addr(), see there for
+details.
+Before using FUNC 03h one must somehow ensure that the desired file is loaded
+(and that it does have initialized the function address via SWI 17h, otherwise
+the pocketstation would crash).
+The FUNC3 address is automatically reset to 0000h when (if) SWI 05h
+(SenseAutoCom) senses new docking.
+Note: The POC-XBOO circuit uses FUNC3 to transfer TTY debug messages.
+
+FUNC 80h..FFh - Custom Function 80h..FFh
+LEN1 is variable (depends on the LEN1 value in Function Table in File Header):
+ ... Send LEN1 Parameter Value(s), max 80h bytes (destroys Kernel when >80h)
+LEN2 is variable (depends on the return value of the 1st function call):
+ ... Get or Send LEN2 Data byte(s), max 80h bytes (clipped to max=80h)
+The function addresses (and LEN1 values) are stored in the Function Table FLASH
+memory (see Pocketstation File Header for details).
+ ;above LEN1 should be 00h..80h (the parameters are stored
+ ;in a 80h-byte buffer in kernel RAM, so len LEN1=81h..FFh would
+ ;destroy the kernel RAM that is located after that buffer)
+Before using FUNC 80h..FFh one must somehow ensure that the desired file is
+loaded (ie. that the function table with the desired functions is mapped to
+flash memory; otherwise the pocketstation would crash).
+
+First Function Call (Pre-Data)
+Incoming parameters on 1st Function Call:
+ r0=flags (09h=Pre-Data to PSX, or 0Ah=Pre-Data from PSX)
+ r1=pointer to parameter buffer (which contains LEN1 bytes) (in Kernel RAM)
+Return Value on 1st Function Call:
+ r0 = Pointer to 64bit memory location (or r0=00000000h=Failed)
+That 64bits are:
+ 0-31 BUF2 address of data buffer (src/dst)
+ 32-63 LEN2 (00000000h..00000080h) (clipped to max 00000080h if bigger)
+dst is written in 8bit units
+src is read in 16bit units (and then split to 8bit units)
+
+Second Function Call (Post-Data)
+Incoming parameters on 2nd Function Call:
+ r0=flags (11h=Post-Data to PSX, 12h=Post-Data from PSX; plus 04h if Bad-Data)
+ r1=pointer to data buffer (which contains LEN2 bytes) (BUF2 address)
+Return Value on 2nd Function Call:
+ There's no return value required on 2nd call (although the kernel
+ functions seem to return the same stuff as on 1st call).
+
+Function flags (r0)
+For each function, there is only one single function vector which is called for
+both To- and From-PSX, and both Pre- and Post-Data, and also on errors. The
+function must decipher the flags in r0 to figure out which of that operations
+it should handle:
+ 0 To-PSX (when used by Command 5Bh)
+ 1 From-PSX (when used by Command 5Ch)
+ 2 Error occurred during Data transfer
+ 3 Pre-Data
+ 4 Post-Data
+ 5-31 Not used (zero)
+There are only six possible flags combinations:
+ 09h Pre-Data to PSX
+ 0Ah Pre-Data from PSX
+ 11h Post-Data to PSX
+ 12h Post-Data from PSX
+ 15h Post-Bad-Data to PSX
+ 16h Post-Bad-Data from PSX
+The kernel doesn't call FUNC 03h if the Error bit is set (ie. Post-Bad-Data
+needs to be handled only by FUNC 80h..FFh, not by FUNC 03h.)
+
+Pocketstation File Header/Icons
+-------------------------------
+
+Pocketstation File Content
+Pocketstation files consists of the following elements (in that order):
+ PSX Title Sector ;80h bytes
+ PSX Colored Icon(s) ;(hdr[02h] AND 0Fh)*80h bytes
+ Pocketstation Saved Snapshot ;800h bytes if hdr[52h]="MCX1", else 0 bytes
+ Pocketstation Function Table ;(hdr[57h]*8+7Fh) AND NOT 7Fh bytes
+ Pocketstation File Viewer Mono Icon ;hdr[50h]*80h bytes
+ Pocketstation Executable Mono Icon List ;hdr[56h]*8 bytes
+ Body (Pocketstation Executable Code/Data, PSX Game Position, Exec-Icons)
+The Title sector contains some information about the size of the above regions,
+but not about their addresses (ie. to find a given region, one must compute the
+size of the preceeding regions).
+
+Special "P" Filename in Directory Sector
+For pocketstation executables, the 7th byte of the filename must be a "P" (for
+other files that location does usually contain a "-", assuming the file uses a
+standard filename, eg. "BESLES-12345abcdefgh" for a Sony licensed european
+title).
+
+Special Pocketstation Entries in the Title Sector at [50h..5Fh]
+ 50h 2 Number of File Viewer Mono Icon Frames (or 0000h=Use Exec-Icons)
+ 52h 4 Pocketstation Identifier ("MCX0"=Normal, "MCX1"=With Snapshot)
+ 56h 1 Number of entries in Executable Mono Icon List (01h..FFh)
+ 57h 1 Number of BU Command 5Bh/5Ch Get/Set Functions (00h..7Fh, usually 00h)
+ 58h 4 Reserved (zero)
+ 5Ch 4 Entrypoint in FLASH1 (ie. Fileoffset plus 02000000h) (bit0=THUMB)
+In normal PSX files, the region at 50h..5Fh is usually zerofilled. For more
+info on the standard entries in the Title Sector (and for info on Directory
+Entries), see:
+--> Memory Card Data Format
+
+Snapshot Region (in "MCX1" Files only)
+For a load-able snapshot the Snapshot ID must be 01h,00h,"SE", the Kernel uses
+snapshots only once (after loading a snapshot, it forcefully changes the ID to
+00h,00h,"SE" in FLASH memory).
+ 000h r1..r12 (ie. without r0)
+ 030h r13_usr (sp_usr)
+ 034h r14_usr (lr_usr)
+ 038h r15 (pc)
+ 03Ch psr_fc
+ 040h Snapshot ID (0xh,00h,"SE")
+ 044h unused (3Ch bytes)
+ 200h Copy of user RAM at 200h..7FFh
+For MCX1 files, snapshots can be automatically loaded and saved via the SWI
+09h, DoExecute function (the snapshot handling seems to be bugged though; see
+SWI 09h for details).
+
+Function Table (FUNC 80h..FFh)
+The table can contain 00h..7Fh entries, for FUNC 80h..FFh. Each entry occupies
+8 bytes:
+ 00h 4 LEN1 (00000000h..00000080h) (destroys Kernel RAM if bigger)
+ 04h 4 Function Address (bit0 can be set for THUMB code)
+If the number of table entries isn't a multiple of 10h, then the table should
+be zero-padded to a multiple of 80h bytes (the following File Viewer Mono Icon
+data is located on the next higher 80h-byte boundary after the Function Table).
+For details see BU Commands 5Bh and 5Ch.
+
+File Viewer Mono Icon
+Animation Length (0001h..any number) (icon frames) is stored in hdr[50h], for
+the File Viewer Icon, the Animation Delay is fixed (six 30Hz units per frame).
+The File Viewer Icon is shown in the Directory Viewer (which is activated when
+holding the Down-button pressed for some seconds in the GUI screen with the
+speaker and memory card symbols, and which shows icons for all files, including
+regular PSX game positions, whose colored icons are converted without any
+contrast optimizations to unidentify-able dithered monochrome icons). If the
+animation length of the File Viewer Icon is 0000h, then the Directory Viewer
+does instead display the first Executable Mono Icon.
+Each icon frame is 32x32 pixels with 1bit color depth (32 words, =128 bytes),
+ 1st word = top-most scanline, 31st word = bottom-most scanline
+ bit0 = left-most pixel, bit31 = right-most pixel (0=white, 1=black)
+A normal icon occupies 80h bytes, animated icons have more than one frame and
+do occupy N*80h bytes.
+
+Executable Mono Icon List
+The number of entries in the Executable Mono Icon List is specified in hdr[56h]
+(usually 01h). Each entry in the Icon List occupies 8 bytes:
+ 00h 2 Animation Length (0001h..any number) (icon frames)
+ 02h 2 Animation Delay (N 30Hz units per icon frame)
+ 04h 4 Address of icon frame(s) in Virtual FLASH (at 02000000h and up)
+The icon frame(s) can be anywhere on a word-aligned location in the file Body
+(as specified in the above Address entry), the format of the frame(s) is the
+same as for File Viewer Mono Icons (see there).
+The Executable Icons are shown in the Executable File Selection Menu (which
+occurs when pressing Left/Right buttons in the GUI). Pressing Fire button in
+that menu starts the selected executable. If the Icon List has more than 1
+entry, then pressing Up/Down buttons moves to the previous/next entry (this
+just allows to view the corresponding icons, but doesn't have any other
+purpose, namely, the current list index is NOT passed to the game when starting
+it).
+The Executable Mono Icon List is usually zero-padded to 80h-bytes size
+(although that isn't actually required, the following file Body could start at
+any location).
+
+Entrypoint
+The whole file (including the header and icons) gets mapped to 02000000h and
+up. The entrypoint can be anywhere in the file Body, and it gets called with a
+parameter value in r0 (when started by the GUI, that parameter is always zero,
+but it may be nonzero when the executable was started by a game, ie. the
+<param> from SWI 08h, PrepareExecute, or the <param> from BU Command 59h).
+Caution: Games (and GUI) are started with the ARM CPU running in Non-privileged
+User Mode (however, there are several ways to hook IRQ/FIQ handlers, and from
+there one can switch to Privileged System Mode).
+
+Returning to the GUI
+Games should always include a way to return to the GUI (eg. an option in the
+game over screen, a key combination, a watchdog timer, and/or the docking
+signal) (conventionally, games should prompt Exit/Continue when holding Fire
+pressed for 5 seconds), otherwise it wouldn't be possible to start other games
+- except by pushing the Reset button (which is no good idea since the bizarre
+BIOS reset handler does reset the RTC time for whatever reason).
+The kernel doesn't pass any return address to the entrypoint (neither in R14,
+nor on stack). To return control to the GUI, use SWI functions
+PrepareExecute(1,0,GetDirIndex()+30h), and then DoExecute(0).
+
+Pocketstation File Images
+-------------------------
+
+Pocketstation files are normally stored in standard Memory Card images,
+--> Memory Card Images
+
+Pocketstation specific files
+Aside from that standard formats, there are two Pocketstation specific formats,
+the "SC" and "SN" variants. Both contain only the raw file, without any
+Directory sectors, and thus not including a "BESLESP12345"-style filename
+string. The absence of the filename means that a PSX game couldn't (re-)open
+these files via filenames, so they are suitable only for "standalone"
+pocketstation games.
+
+Pocketstation .BIN Files ("SC" variant)
+Contains the raw Pocketstation Executable (ie. starting with the "SC" bytes in
+the title sector, followed by icons, etc.), the filesize should be padded to a
+2000h-byte block boundary.
+
+Pocketstation .BIN Files ("SN" variant)
+This is a strange incomplete .BIN file variant which starts with a 4-byte ID
+("SN",00h,00h), which is directly followed by executable code, without any
+title sector, and without any icons.
+ It seems as if the file (including the 4-byte ID) is intended to be
+ mapped to address 02000000h, and that the entrypoint is fixed at
+ 02000004h (in ARM state).
+ Since the File doesn't have a valid file header with "SC" and "MCXn" IDs,
+ it won't be recognized by real hardware, the PSX BIOS would treat it as
+ a corrupted/deleted file, the Pocketstation BIOS would treat it as a
+ non-executable file.
+ So, that fileformat is apparently working only on whatever emulators,
+ apparently on the one developed by SN Systems.
+ If one should want to use that files on real hardware, one could add
+ a 2000h byte stub at the begin of the file; with valid headers, and
+ with a small executable that remaps the "SN" stuff to 02000000h via
+ the F_BANK_VAL registers.
+ Ah, and the "SN" files seem to access RAM at 01000000h and up, unknown
+ if RAM is mirrored to that location on real hardware, reportedly that
+ region is unused... and doesn't contain RAM...?
+ Some games use The Undefined Instruction for TTY Output.
+ Most games do strange 8bit writes to LCD_MODE+0 and LCD_MODE+1
+ The games usually don't allow to return to the GUI (except by Reset).
+The filesize is don't care (no padding to block, sector, word, or halfword
+boundaries required).
+
+Pocketstation XBOO Cable
+------------------------
+
+This circuit allows to connect a pocketstation to PC parallel port, allowing to
+upload executables to real hardware, and also allowing to download TTY debug
+messages (particulary useful as the 32x32 pixel LCD screen is ways too small to
+display any detailed status info).
+
+POC-XBOO Circuit
+Use a standard parallel port cable (with 36pin centronics connector or 25pin DB
+connector) and then build a small adaptor like this:
+ Pin CNTR DB25 Pocketstation _______________________
+ ACK 10 10 --------- 1 JOYDTA | | | |
+ D0 2 2 --------- 2 JOYCMD | 9 7 6 | 5 4 3 | 2 1 | CARD
+ GND 19-30 18-25 ------- 4 GND |_______|_______|_______|
+ D1 3 3 --------- 6 /JOYSEL _______________________
+ D2 4 4 --------- 7 JOYCLK | | | |
+ PE 12 12 --------- 9 /JOYACK (/IRQ7) | 9 8 7 | 6 5 4 | 3 2 1 | PAD
+ NC -------------------- 8 /JOYGUN (/IRQ10) \______|_______|______/
+ NC -------------------- 3 7.5V (rumble.supply)
+ SUPPLY.5V --|>|---|>|-- 5 3.5V (VCC) (eg. PC's +5V via two 1N4001 diodes)
+ SUPPLY.0V ------------- 4 GND (not needed when same as GND on CNTR/DB25)
+The circuit is same as for "Direct Pad Pro" (but using a memory card connector
+instead of joypad connector, and needing +5V from PC power supply instead of
+using parallel port D3..D7 as supply). Note: IRQ7 is optional (for faster/early
+timeout).
+
+POC-XBOO Upload
+The upload function is found in no$gba "Utility" menu. It does upload the
+executable and autostart it via standard memory card/pocketstation commands
+(ie. it doesn't require any special transmission software installed on the
+pocketstation side).
+Notes: Upload is overwriting ALL files on the memory card, and does then
+autostart the first file. Upload is done as "read and write only if different",
+this provides faster transfers and higher lifetime.
+
+POC-XBOO TTY Debug Messages
+TTY output is conventionally done by executing the ARM CPU's Undefined Opcode
+with an ASCII character in R0 register (for that purpose, the undef opcode
+handler should simply point to a MOVS PC,LR opcode).
+That kind of TTY output works in no$gba's pocketstation emulation. It can be
+also used via no$gba's POC-XBOO cable, but requires some small customization in
+the executable:
+First of, the executable needs "TTY+" ID in some reserved bytes of the title
+sector (telling the xboo uploader to stay in transmission mode and to keep
+checking for TTY messages after the actual upload):
+ TitleSector[58h] = "TTY+"
+With that ID, and with the XBOO-hardware being used, the game will be started
+with "TTY+" in R0 (notifying it that the XBOO hardware is present, and that it
+needs to install special transmission handlers):
+ ;------------------
+ .data?
+ org 200h
+ ...
+ tty_bufsiz equ 128 ;max=128=fastest (can be smaller if you are short of RAM)
+ func3_info: ;\ ;\
+ func3_buf_base dd 0 ;fixed="func3_buf" ; ; func3_info+00h
+ func3_buf_len dd 0 ;range=0..128 ;/ ; func3_info+04h
+ func3_stack dd 0 ; func3_info+08h
+ func3_buffer: defs tty_bufsiz ;/ func3_info+0Ch
+ ptr_to_comflags dd 0
+ ...
+ .code
+ ...
+ ;------------------
+ tty_wrchr: ;in: r0=char
+ dd 0e6000010h ;=undef opcode ;-Write chr(r0) to TTY
+ bx lr
+ ;------------------
+ init_tty: ;in: r0=param (from entrypoint)
+ ldr r1,=2B595454h ;"TTY+" ;\check if xboo-cable present
+ cmp r1,r0 ; (r0=incoming param from
+ beq @@tty_by_xboo_cable ;/executable's entrypoint)
+ ;- - -
+ mov r1,0 ;\dummy und_handler
+ ldr r2,=0e1b0f00eh ;=movs r15,r14 ; (just return from exception,
+ str r2,[r1,04h] ;und_handler ;/for normal cable-less mode)
+ b @@finish
+ ;---
+ @@tty_by_xboo_cable:
+ swi 17h ;GetPtrToFunc3addr() ;\
+ ldr r1,=(tty_func3_handler AND 0ffffh) ; init FUNC3 aka TTY handler
+ strh r1,[r0] ;/
+ ldr r1,=func3_info ;\
+ mov r0,0 ;\ ; mark TTY as len=empty
+ str r0,[r1,4] ;func3_buf_len ;/ ; and
+ add r0,r1,0ch ;=func3_buffer ;\ ; init func3 base
+ str r0,[r1,0] ;func3_buf_base ;/ ;/
+ mov r1,0 ;\
+ ldr r2,=0e59ff018h ;=ldr r15,[pc,NN] ;
+ str r2,[r1,04h] ;und_handler ; special xboo und_handler
+ add r2,=tty_xboo_und_handler ;
+ str r2,[r1,24h] ;und_vector ;/
+ @@finish:
+ swi 06h ;GetPtrToComFlags() ;\
+ ldr r1,=ptr_to_comflags ; get ptr to ComFlags
+ str r0,[r1] ;/
+ bx lr
+ ;------------------
+ tty_xboo_und_handler: ;in: r0=char
+ ldr r13,=func3_info ;aka sp_und ;-base address (in sp_und)
+ str r12,[r13,8] ;func3_stack ;-push r12
+ @@wait_if_buffer_full: ;\
+ ldr r12,=ptr_to_comflags ; ;\exit if execute file request
+ ldr r12,[r12] ;ptr to ComFlags ; ; ComFlg.Bit11 ("bu_cmd_59h"),
+ ldr r12,[r12] ;read ComFlags ; ; ie. allow that flag to be
+ tst r12,1 shl 11 ;test bit11 ; ; processed by main program,
+ bne @@exit ; ;/without hanging here
+ ldrb r12,[r13,4] ;func3_buf_len ; wait if buffer full
+ cmp r12,tty_bufsiz ; (until drained by FIQ)
+ beq @@wait_if_buffer_full ;/
+ mov r12,1bh+0c0h ;mode=und, FIQ/IRQ=off ;\disable FIQ (no COMMUNICATION
+ mov cpsr_ctl,r12 ;/interrupt during buffer write)
+ ldrb r12,[r13,4] ;func3_buf_len ;\
+ add r12,1 ;raise len ; write char to buffer
+ strb r12,[r13,4] ;func3_buf_len ; and raise buffer length
+ add r12,0ch-1 ;=func3_buffer+INDEX ;
+ strb r0,[r13,r12] ;append char to buf ;/
+ @@exit:
+ ldr r12,[r13,8] ;func3_stack ;-pop r12
+ movs r15,r14 ;return from exception (and restore old IRQ/FIQ state)
+ ;------------------
+ tty_func3_handler: ;in: r0=flags, r1=ptr
+ tst r0,10h ;test if PRE/POST data (pre: Z, post: NZ)
+ ;ldreq r1,[r1] ;read 32bit param (aka the four LEN1 bytes of FUNC3)
+ ldr r0,=func3_info ;ptr to two 32bit values (FUNC3 return value)
+ movne r1,0 ;\for POST data: mark buffer empty
+ strne r1,[r0,4] ;func3_buf_len=0 ;/
+ bx lr ;-for PRE data: return r0=func3_info
+Usage: Call "init_tty" at the executable's entrypoint (with incoming R0 passed
+on). Call "tty_wrchr" to output ASCII characters.
+Note: The TTY messages are supported only in no$gba debug version (not no$gba
+gaming version).
+
+Serial Port (SIO)
+-----------------
+
+1F801050h SIO_TX_DATA (W)
+ 0-7 Data to be sent
+ 8-31 Not used
+Writing to this register starts transmit (if, or as soon as, TXEN=1 and CTS=on
+and SIO_STAT.2=Ready). Writing to this register while SIO_STAT.0=Busy causes
+the old value to be overwritten.
+The "TXEN=1" condition is a bit more complex: Writing to SIO_TX_DATA latches
+the current TXEN value, and the transfer DOES start if the current TXEN value
+OR the latched TXEN value is set (ie. if TXEN gets cleared after writing to
+SIO_TX_DATA, then the transfer may STILL start if the old latched TXEN value
+was set; this appears for SIO transfers in Wipeout 2097).
+
+1F801050h SIO_RX_DATA (R)
+ 0-7 Received Data (1st RX FIFO entry) (oldest entry)
+ 8-15 Preview (2nd RX FIFO entry)
+ 16-23 Preview (3rd RX FIFO entry)
+ 24-31 Preview (4th RX FIFO entry) (5th..8th cannot be previewed)
+A data byte can be read when SIO_STAT.1=1. Data should be read only via 8bit
+memory access (the 16bit/32bit "preview" feature is rather unusable).
+
+1F801054h SIO_STAT (R)
+ 0 TX Ready Flag 1 (1=Ready/Started) (depends on CTS) (TX requires CTS)
+ 1 RX FIFO Not Empty (0=Empty, 1=Not Empty)
+ 2 TX Ready Flag 2 (1=Ready/Finished) (depends on TXEN and on CTS)
+ 3 RX Parity Error (0=No, 1=Error; Wrong Parity, when enabled) (sticky)
+ 4 RX FIFO Overrun (0=No, 1=Error; Received more than 8 bytes) (sticky)
+ 5 RX Bad Stop Bit (0=No, 1=Error; Bad Stop Bit) (when RXEN) (sticky)
+ 6 RX Input Level (0=Normal, 1=Inverted) ;only AFTER receiving Stop Bit
+ 7 DSR Input Level (0=Off, 1=On) (remote DTR) ;DSR not required to be on
+ 8 CTS Input Level (0=Off, 1=On) (remote RTS) ;CTS required for TX
+ 9 Interrupt Request (0=None, 1=IRQ) (sticky)
+ 10 Unknown (always zero)
+ 11-25 Baudrate Timer (15bit timer, decrementing at 33MHz)
+ 26-31 Unknown (usually zero, sometimes all bits set)
+Note: Bit0 gets cleared after sending the Startbit, Bit2 gets cleared after
+sending all bits up to including the Stopbit.
+
+1F801058h SIO_MODE (R/W) (eg. 004Eh --> 8N1 with Factor=MUL16)
+ 0-1 Baudrate Reload Factor (1=MUL1, 2=MUL16, 3=MUL64) (or 0=STOP)
+ 2-3 Character Length (0=5bits, 1=6bits, 2=7bits, 3=8bits)
+ 4 Parity Enable (0=No, 1=Enable)
+ 5 Parity Type (0=Even, 1=Odd) (seems to be vice-versa...?)
+ 6-7 Stop bit length (0=Reserved/1bit, 1=1bit, 2=1.5bits, 3=2bits)
+ 8-15 Not used (always zero)
+
+1F80105Ah SIO_CTRL (R/W)
+ 0 TX Enable (TXEN) (0=Disable, 1=Enable, when CTS=On)
+ 1 DTR Output Level (0=Off, 1=On)
+ 2 RX Enable (RXEN) (0=Disable, 1=Enable) ;Disable also clears RXFIFO
+ 3 TX Output Level (0=Normal, 1=Inverted, during Inactivity & Stop bits)
+ 4 Acknowledge (0=No change, 1=Reset SIO_STAT.Bits 3,4,5,9) (W)
+ 5 RTS Output Level (0=Off, 1=On)
+ 6 Reset (0=No change, 1=Reset most SIO_registers to zero) (W)
+ 7 Unknown? (read/write-able when FACTOR non-zero) (otherwise always zero)
+ 8-9 RX Interrupt Mode (0..3 = IRQ when RX FIFO contains 1,2,4,8 bytes)
+ 10 TX Interrupt Enable (0=Disable, 1=Enable) ;when SIO_STAT.0-or-2 ;Ready
+ 11 RX Interrupt Enable (0=Disable, 1=Enable) ;when N bytes in RX FIFO
+ 12 DSR Interrupt Enable (0=Disable, 1=Enable) ;when SIO_STAT.7 ;DSR=On
+ 13-15 Not used (always zero)
+
+1F80105Ch SIO_MISC (R/W)
+This is an internal register, which usually shouldn't be accessed by software.
+Messing with it has rather strange effects: After writing a value "X" to this
+register, reading returns "X ROR 8" eventually "ANDed with 1F1Fh and ORed with
+C0C0h or 8080h" (depending on the character length in SIO_MODE).
+
+1F80105Eh SIO_BAUD (R/W) (eg. 00DCh --> 9600 bauds; when Factor=MUL16)
+ 0-15 Baudrate Reload value for decrementing Baudrate Timer
+The Baudrate is calculated (based on SIO_BAUD, and on Factor in SIO_MODE):
+ BitsPerSecond = (44100Hz*300h) / MIN(((Reload*Factor) AND NOT 1),Factor)
+
+SIO_TX_DATA Notes
+The hardware can hold (almost) 2 bytes in the TX direction (one being currently
+transferred, and, once when the start bit was sent, another byte can be stored
+in SIO_TX_DATA). When writing to SIO_TX_DATA, both SIO_STAT.0 and SIO_STAT.2
+become zero. As soon as the transfer starts, SIO_STAT.0 becomes set (indicating
+that one can write a new byte to SIO_TX_DATA; although the transmission is
+still busy). As soon as the transfer of the most recently written byte ends,
+SIO_STAT.2 becomes set.
+
+SIO_RX_DATA Notes
+The hardware can hold 8 bytes in the RX direction (when receiving further
+byte(s) while the RX FIFO is full, then the last FIFO entry will by overwritten
+by the new byte, and SIO_STAT.4 gets set; the hardware does NOT automatically
+disable RTS when the FIFO becomes full).
+Data can be read from SIO_RX_DATA when SIO_STAT.1 is set, that flag gets
+automatically cleared after reading from SIO_RX_DATA (unless there are still
+further bytes in the RX FIFO). Note: The hardware does always store incoming
+data in RX FIFO (even when Parity or Stop bits are invalid).
+Note: A 16bit read allows to read two FIFO entries at once; nethertheless, it
+removes only ONE entry from the FIFO. On the contrary, a 32bit read DOES remove
+FOUR entries (although, there's nothing that'd indicate if the FIFO did
+actually contain four entries).
+Reading from Empty RX FIFO returns either the most recently received byte or
+zero (the hardware stores incoming data in ALL unused FIFO entries; eg. if five
+entries are used, then the data gets stored thrice, after reading 6 bytes, the
+FIFO empty flag gets set, but nethertheless, the last byte can be read two more
+times, but doing further reads returns 00h).
+
+Interrupt Acknowledge Notes
+First reset I_STAT.8, then set SIO.CTRL.4 (when doing it vice-versa, the
+hardware may miss a new IRQ which may occur immediately after setting
+SIO.CTRL.4) (and I_STAT.8 is edge triggered, so that bit can be reset even
+while SIO_STAT.9 is still set).
+When acknowledging via SIO_CTRL.4 with the enabled condition(s) in
+SIO_CTRL.10-12 still being true (eg. the RX FIFO is still not empty): the IRQ
+does trigger again (almost) immediately (it goes off only for a very short
+moment; barely enough to allow I_STAT.8 to sense a edge).
+
+SIO_BAUD Notes
+Timer reload occurs when writing to SIO_BAUD, and, automatically when the
+Baudrate Timer reaches zero. There should be two 16bit SIO timers (for TX and
+RX), the upper 15bit of one of that timers can be read from SIO_STAT (not sure
+which one, and no idea if there's a way to read the other timer, too).
+Or... maybe there is only ONE timer, and RX/TX are separated only by separate
+"timer ellapsed" counters, in that case the MUL1 factor won't work properly,
+but, with the MUL16 or MUL64 factors, RX could start anytime (eg. when TX has
+already ellapsed a bunch of times)...?
+The maximum baud rate may vary depending on the length and quality of the
+cable, whether and how many inverters and anti-inverters are used (on the
+mainboard and in external adaptor, and on whether signals are externally
+converted to +/-12V levels)... anyways, rates up to 9600 baud should be working
+in all cases.
+However, running in no$psx, Wipeout 2097 seems to use about 2 million bauds...
+although, in older no$psx versions, I believe I did see it using some kind of
+baudrate detection, where it did try different rates in steps of 200 bauds or
+so...?
+
+SIO Ports vs JOY Ports
+SIO uses I/O Addresses 1F801050h..1F80105Fh, which seem to be organized similar
+to the Controller/Memory Card registers at 1F801040h..1F80104Fh, though not
+identical, and with an additional register at 1F80105Ch, which has no
+corresponding port at 1F80104Ch.
+SIO_BAUD is <effectively> same as for JOY_BAUD, but, <internally> they are a
+bit different:
+ JOY_BAUD is multiplied by Factor, and does then ellapse "2" times per bit.
+ SIO_BAUD is NOT multiplied, and, instead, ellapses "2*Factor" times per bit.
+Unlike for the Controller/Memory Card ports, the data is transferred without
+CLK signal, instead, it's using RS232 format, ie. the transfer starts with a
+start bit, and is then transferred at a specific baudrate (which must be
+configured identically at the receiver side). For RS232, data is usually 8bit,
+and may optionally end with a parity bit, and one or two stop bits.
+
+Note
+For SIO Pinouts, PSone SIO upgrading, and for building RS232 adaptors, see:
+--> Pinouts - SIO Pinouts
+Aside from the internal SIO port, the PSX BIOS supports two additional external
+serial ports, connected to the expansion port,
+--> EXP2 Dual Serial Port (for TTY Debug Terminal)
+
+SIO Games
+The serial port is used (for 2-player link) by Wipeout 2097 (that game
+accidently assumes BAUDs based on 64*1024*1025 Hz rather than on 600h*44100
+Hz).
+Ridge Racer Revolution is also said to support 2P link.
+Keitai Eddy seems to allow to connect a mobile phone to the SIO port (the games
+CD cover suggests so; this seems to be something different than the "normal"
+I-Mode adaptor, which would connect to controller port, not to SIO port).
+
+8251A Note
+The Playstation Serial Port is apparently based/inspired on the Intel 8251A
+USART chip; which has very similar 8bit Mode/Command/Status registers.
+
+Expansion Port (PIO)
+--------------------
+
+Expansion Port can contain ROM, RAM, I/O Ports, etc. For ROM, the first 256
+bytes would contain the expansion ROM header.
+
+For region 1, the CPU outputs a chip select signal (CPU Pin 98, /EXP).
+For region 2, the CPU doesn't produce a chip select signal (the region is
+intended to contain multiple I/O ports, which do require an address decoder
+anyways, that address decoder could treat any /RD or /WR with A13=Hi and A23=Hi
+and A22=Lo as access to expansion region 2 (for /WR, A22 may be ignored;
+assuming that the BIOS is read-only).
+
+Size/Bus-Width
+The BIOS initalizes Expansion Region 1 to 512Kbyte with 8bit bus, and Region 2
+to 128 bytes with 8bit bus. However, the size and data bus-width of these
+regions can be changed, see:
+--> Memory Control
+For Region 1, 32bit reads are supported even in 8bit mode (eg. 32bit opcode
+fetches are automatically processed as four 8bit reads).
+For Region 2, only 8bit access seems to be supported (except that probably
+16bit mode allows 16bit access), anyways, larger accesses seem to cause
+exceptions... not sure if that can be disabled...?
+
+Expansion 1 - EXP1 - Intended to contain ROM
+--> EXP1 Expansion ROM Header
+
+Expansion 2 - EXP2 - Intended to contain I/O Ports
+--> EXP2 Dual Serial Port (for TTY Debug Terminal)
+--> EXP2 DTL-H2000 I/O Ports
+--> EXP2 Post Registers
+--> EXP2 Nocash Emulation Expansion
+
+Expansion 3 - EXP3 - Intended to contain RAM
+Not used by BIOS nor by any games. Seems to contain 1Mbyte RAM with 16bit
+databus (ie. 512Kx16) in DTL-H2000.
+
+Other Expansions
+Aside from the above, the Expansion regions can be used for whatever purpose,
+however, mind that the BIOS is reading from the ROM header region, and is
+writing to the POST register (so 1F000000h-1F0000FFh and 1F802041h should be
+used only if the hardware isn't disturbed by those accesses).
+
+Missing Expansion Port
+The expansion port is installed only on older PSX boards, newer PSX boards and
+all PSone boards don't have that port. However, the CPU should still output all
+expansion signals, and there should be big soldering points on the board, so
+it'd be easy to upgrade the console.
+
+Latched Address Bus
+Note that A0..A23 are latched outputs, so they can be used as general purpuse
+24bit outputs, provided that the system bus isn't used for other purposes (such
+like /BIOS, /SPU, /CD accesses) (A0..A23 are not affected by Main RAM and GPU
+addressing, nor by internal I/O ports like Timer and IRQ registers).
+
+EXP1 Expansion ROM Header
+-------------------------
+
+Expansion 1 - ROM Header (accessed with 8bit databus setting)
+ Address Size Content
+ 1F000000h 4 Post-Boot Entrypoint (eg. 1F000100h and up)
+ 1F000004h 2Ch Post-Boot ID ("Licensed by Sony Computer Entertainment Inc.")
+ 1F000030h 50h Post-Boot TTY Message (must contain at least one 00h byte)
+ 1F000080h 4 Pre-Boot Entrypoint (eg. 1F000100h and up)
+ 1F000084h 2Ch Pre-Boot ID ("Licensed by Sony Computer Entertainment Inc.")
+ 1F0000B0h 50h Not used (should be zero, but may contain code/data/io)
+ 1F000100h .. Code, Data, I/O Ports, etc.
+The entrypoints are called if their corresonding ID strings are present, return
+address to BIOS is passed in R31, so the expansion ROM may return control to
+BIOS, if that should be desired.
+Aside from verifying the IDs, the BIOS will also display the Post-Boot ID
+string (and the following message string) via TTY (done right before calling
+the Post-Boot Entrypoint).
+
+Pre-Boot Function
+The Pre-Boot function is called almost immediately after Reset, with only some
+Memory Control registers initialized, the BIOS function vectors at A0h, B0h,
+and C0h are NOT yet initialized, so the Pre-Boot function can't use them.
+
+Post-Boot Function
+The Post-Boot function gets called while showing the "PS" logo, but before
+loading the .EXE file. The BIOS function vectors at A0h, B0h, and C0h are
+already installed and can be used by the Post-Boot Function.
+Note that the Post-Boot Function is called ONLY when the "PS" logo is shown
+(ie. not if the CDROM drive is empty, or if it contains an Audio CD).
+
+Mid-Boot Hook
+One common trick to hook the Kernel after BIOS initialization, but before CDROM
+loading is to use the Pre-Boot handler to set a COP0 opcode fetch hardware
+breakpoint at 80030000h (after returning from the Pre-Boot handler, the Kernel
+will initialize important things like A0h/B0h/C0h tables, and will then break
+again when starting the GUI code at 80030000h) (this trick is used by Action
+Replay v2.0 and up).
+
+Note
+Expansion ROMs are most commonly used in cheat devices,
+--> Cheat Devices
+
+EXP2 Dual Serial Port (for TTY Debug Terminal)
+----------------------------------------------
+
+SCN2681 Dual Asynchronous Receiver/Transmitter (DUART)
+The PSX/PSone retail BIOS contains some TTY Debug Terminal code; using an
+external SCN2681 chip which can be connected to the expansion port.
+Whilst supported by all PSX/PSone retail BIOSes on software side, there aren't
+any known PSX consoles/devboards/expansions actually containing DUARTs on
+hardware side.
+
+1F802023h/Read - RHRA - DUART Rx Holding Register A (FIFO) (R)
+1F80202Bh/Read - RHRB - DUART Rx Holding Register B (FIFO) (R)
+1F802023h/Write - THRA - DUART Tx Holding Register A (W)
+1F80202Bh/Write - THRB - DUART Tx Holding Register B (W)
+ 7-0 Data (aka Character)
+The hardware can hold max 2 Tx characters per channel (1 in the THR register,
+and one currently processed in the Tx Shift Register), and max 4 Rx characters
+(3 in the RHR FIFO, plus one in the Rx Shift Register) (when receiving a 5th
+character, the "old newest" value in the Rx Shift Register is lost, and the
+overrun flag is set).
+
+1F802020h/FirstAccess - MR1A - DUART Mode Register 1.A (R/W)
+1F802028h/FirstAccess - MR1B - DUART Mode Register 1.B (R/W)
+ 7 RxRTS Control (0=No, 1=Yes)
+ 6 RxINT Select (0=RxRDY, 1=FFULL)
+ 5 Error Mode (0=Char, 1=Block)
+ 4-3 Parity Mode (0=With Parity, 1=Force Parity, 2=No Parity, 3=Multidrop)
+ 2 Parity Type (0=Even, 1=Odd)
+ 1-0 Bits per Character (0=5bit, 1=6bit, 2=7bit, 3=8bit)
+Note: In block error mode, block error conditions must be cleared by using the
+error reset command (command 4) or a receiver reset (command 2).
+
+1F802020h/SecondAccess - MR2A - DUART Mode Register 2.A (R/W)
+1F802028h/SecondAccess - MR2B - DUART Mode Register 2.B (R/W)
+ 7-6 Channel Mode (0=Normal, 1=Auto-Echo, 2=Local loop, 3=Remote loop)
+ 5 TxRTS Control (0=No, 1=Yes) (when 1 --> OP0=RTSA / OP1=RTSB)
+ 4 CTS Enable (0=No, 1=Yes) (when 1 --> IP0=CTSA / IP1=CTSB)
+ 3-0 Tx Stop Bit Length (00h..0Fh = see below)
+Stop Bit Lengths:
+ 0=0.563 1=0.625 2=0.688 3=0.750 4=0.813 5=0.875 6=0.938 7=1.000
+ 8=1.563 9=1.625 A=1.688 B=1.750 C=1.813 D=1.875 E=1.938 F=2.000
+Add 0.5 to values shown for 0..7 if channel is programmed for 5 bits/char.
+
+1F802021h/Write - CSRA - DUART Clock Select Register A (W)
+1F802029h/Write - CSRB - DUART Clock Select Register B (W)
+ 7-4 Rx Clock Select (0..0Ch=See Table, 0Dh=Timer, 0Eh=16xIP, 0Fh=1xIP)
+ 3-0 Tx Clock Select (0..0Ch=See Table, 0Dh=Timer, 0Eh=16xIP, 0Fh=1xIP)
+The 2681 has some sets of predefined baud rates (set1/set2 selected via ACR.7),
+additionally, in BRG Test Mode, set3/set4 are used instead of set1/set2), the
+baud rates for selections 00h..0Dh are:
+ Rate 00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 0Ah 0Bh 0Ch
+ Set1 50 110 134.5 200 300 600 1200 1050 2400 4800 7200 9600 38400
+ Set2 75 110 134.5 150 300 600 1200 2000 2400 4800 1800 9600 19200
+ Set3 4800 880 1076 19200 28800 57600 115200 1050 57600 4800 57600 9600 38400
+ Set4 7200 880 1076 14400 28800 57600 115200 2000 57600 4800 14400 9600 19200
+Selection 0Eh/0Fh are using an external clock source (derived from
+IP3,IP4,IP5,IP6 pins; for TxA,RxA,TxB,RxB respectively).
+
+1F802022h/Write - CRA - DUART Command Register A (W)
+1F80202Ah/Write - CRB - DUART Command Register B (W)
+ 7 Not used (should be 0)
+ 6-4 Miscellaneous Commands (0..7 = see below)
+ 3 Disable Tx (0=No change, 1=Disable)
+ 2 Enable Tx (0=No change, 1=Enable) ;Don't use with Command 3 (Reset Rx)
+ 1 Disable Rx (0=No change, 1=Disable)
+ 0 Enable Rx (0=No change, 1=Enable) ;Don't use with Command 2 (Reset Tx)
+The command values for CRA (or CRB) are:
+ 0 No command ;no effect
+ 1 Reset MR pointer ;force "FirstAccess" state for MR1A (or MR1B) access
+ 2 Reset receiver ;reset RxA (or RxB) registers, disable Rx, flush Fifo
+ 3 Reset transmitter ;reset TxA (or TxB) registers
+ 4 Reset Error Flags ;reset SRA.7-4 (or SRB.7-4) to zero
+ 5 Reset Break-Change IRQ Flag ;reset ISR.2 (or ISR.6) to zero
+ 6 Start break ;after current char, pause Tx with TxDA=Low (or TxDB=Low)
+ 7 Stop break ;output one High bit, then continue Tx (ie. undo pause)
+Access to the upper four bits of the command register should be separated by 3
+edges of the X1 clock. A disabled transmitter cannot be loaded.
+
+1F802025h/Read - ISR - DUART Interrupt Status Register (R)
+1F802025h/Write - IMR - DUART Interrupt Mask Register (W)
+ 7 Input Port Change (0=No, 1=Yes) (Ack via reading IPCR) ;see ACR.3-0
+ 6 Break Change B (0=No, 1=Yes) (Ack via CRB/Command5)
+ 5 RxRDYB/FFULLB (0=No, 1=Yes) (Ack via reading data) ;see MR1B.6
+ 4 THRB Empty (TxRDYB) (0=No, 1=Yes) (Ack via writing data) ;same as SRB.2
+ 3 Counter Ready (0=No, 1=Yes) (Ack via CT_STOP)
+ 2 Break Change A (0=No, 1=Yes) (Ack via CRA/Command5)
+ 1 RxRDYA/FFULLA (0=No, 1=Yes) (Ack via reading data) ;see MR1A.6
+ 0 THRA Empty (TxRDYA) (0=No, 1=Yes) (Ack via writing data) ;same as SRA.2
+
+1F802021h/Read - SRA - DUART Status Register A (R)
+1F802029h/Read - SRB - DUART Status Register B (R)
+ 7 Rx Received Break* (0=No, 1=Yes) ;received 00h without stop bit
+ 6 Rx Framing Error* (0=No, 1=Yes) ;received data without stop bit
+ 5 Rx Parity Error* (0=No, 1=Yes) ;received data with bad parity
+ 4 Rx Overrun Error (0=No, 1=Yes) ;Rx FIFO full + RxShiftReg full
+ 3 Tx Underrun (TxEMT) (0=No, 1=Yes) ;both TxShiftReg and THR empty
+ 2 Tx THR Empty (TxRDY) (0=No, 1=Yes) ;same as ISR.0 / ISR.4
+ 1 Rx FIFO Full (FFULL) (0=No, 1=Yes) ;set upon 3 or more characters
+ 0 Rx FIFO Not Empty (RxRDY) (0=No, 1=Yes) ;set upon 1 or more characters
+Bit7-5 are appended to the corresponding data character in the receive FIFO. A
+read of the status provides these bits (7:5) from the top of the FIFO together
+with bits (4:0). These bits are cleared by a "reset error status" command. In
+character mode they are discarded when the corresponding data character is read
+from the FIFO. In block error mode, block error conditions must be cleared by
+using the error reset command (command 4x) or a receiver reset.
+
+1F802024h/Write - ACR - DUART Aux. Control Register (W)
+ 7 Select Baud Rate Generator (BRG) Set (0=Set1/Set3, 1=Set2/Set4)
+ 6-4 Counter/Timer Mode and Source (see below)
+ 3-0 IP3..IP0 Change Interrupt Enable Flags (0=Off, 1=On)
+Counter/Timer Mode and Clock Source Settings:
+ Num Mode Clock Source
+ 0h Counter External (IP2)
+ 1h Counter TxCA - 1x clock of Channel A transmitter
+ 2h Counter TxCB - 1x clock of Channel B transmitter
+ 3h Counter Crystal or external clock (x1/CLK) divided by 16
+ 4h Timer External (IP2)
+ 5h Timer External (IP2) divided by 16
+ 6h Timer Crystal or external clock (x1/CLK)
+ 7h Timer Crystal or external clock (x1/CLK) divided by 16
+In Counter Mode, the Counter Ready flag is set on any underflow, and the
+counter wraps to FFFFh and keeps running (but may get stopped by software).
+In Timer Mode, automatic reload occurs on any underflow, the counter flag
+(which can be output to OP3) is toggled on any underflow, but the Counter Ready
+flag is set only on each 2nd underflow (unlike as in Counter mode).
+
+1F802024h/Read - IPCR - DUART Input Port Change Register (R)
+ 7-4 IP3..IP0 Change Occured Flags (0=No, 1=Yes) ;auto reset after read
+ 3-0 Current IP3-IP0 Input states (0=Low, 1=High) ;Same as IP.3-0
+Reading from this register automatically resets IPCR.7-4 and ISR.7.
+
+1F80202Dh/Read - IP - DUART Input Port (R)
+ 7 Not used (always 1)
+ 6-0 Current IP6-IP0 Input states (0=Low, 1=High) ;LSBs = Same as IPCR.3-0
+IP0-6 can be used as general purpose inputs, or for following special purposes:
+ IP6 External RxB Clock ;see CSRB.7-4
+ IP5 External TxB Clock ;see CSRB.3-0
+ IP4 External RxA Clock ;see CSRA.7-4
+ IP3 External TxA Clock ;see CSRA.3-0
+ IP2 External Timer Input ;see AUX.6-4
+ IP1 Clear to Send B (CTSB) ;see MR2B.5
+ IP0 Clear to Send A (CTSA) ;see MR2A.5
+Note: The 24pin chip doesn't have any inputs, the 28pin chip has only one input
+(IP2), the 40pin/44pin chips have seven inputs (IP0-IP6).
+
+1F80202Eh/Write - DUART Set Output Port Bits Command (Set means Out=LOW)
+1F80202Fh/Write - DUART Reset Output Port Bits Command (Reset means Out=HIGH)
+ 7-0 Change "OPR" OP7-OP0 Output states (0=No change, 1=Set/Reset)
+Note: The 24pin chip doesn't have any outputs, the 28pin chip has only two
+outputs (OP0,OP1), the 40pin/44pin chips have eight outputs (OP0-OP7).
+
+1F80202Dh/Write - OPCR - DUART Output Port Configuration Register (W)
+ 7 OP7 (0=OPR.7, 1=TxRDYB)
+ 6 OP6 (0=OPR.6, 1=TxRDYA)
+ 5 OP5 (0=OPR.5, 1=RxRDY/FFULLB)
+ 4 OP4 (0=OPR.4, 1=RxRDY/FFULLA)
+ 3-2 OP3 (0=OPR.3, 1=Clock/Timer Output, 2=TxCB(1x), 3=RxCB(1x))
+ 1-0 OP2 (0=OPR.2, 1=TxCA(16x), 2=TxCA(1x), 3=RxCA(1x))
+Additionally, the OP0 and OP1 outputs are controlled via MR2A.5 and MR2B.5.
+
+1F802022h/Read - - DUART Toggle Baud Rate Generator Test Mode (Read=Strobe)
+1F80202Ah/Read - - DUART Toggle 1X/16X Test Mode (Read=Strobe)
+ 7-0 Not used (just issue a dummy-read to toggle the test mode on/off)
+BGR Test switches between Baud Rate Set1/Set2 and Set3/Set4.
+1X/16X Test switches between whatever...?
+
+1F80202Eh/Read - CT_START - DUART Start Counter Command (Read=Strobe)
+1F80202Fh/Read - CT_STOP - DUART Stop Counter Command (Read=Strobe)
+ 7-0 Not used (just issue a dummy-read to strobe start/stop command)
+Start: Forces reload (copies CTLR/CTUR to CTL/CTU), and starts the timer.
+Stop-in-Counter-Mode: Resets ISR.3, and stops the timer.
+Stop-in-Timer-Mode: Resets ISR.3, but doesn't stop the timer.
+
+1F802026h/Read - CTU - DUART Counter/Timer Current Value, Upper/Bit15-8 (R)
+1F802027h/Read - CTL - DUART Counter/Timer Current Value, Lower/Bit7-0 (R)
+1F802026h/Write - CTUR - DUART Counter/Timer Reload Value, Upper/Bit15-8 (W)
+1F802027h/Write - CTLR - DUART Counter/Timer Reload Value, Lower/Bit7-0 (W)
+The CTLR/CTUR reload value is copied to CTL/CTU upon Start Counter Command. In
+Timer mode (not in Counter mode), it is additionally copied automatically when
+the timer undeflows.
+
+1F80202Ch - N/A - DUART Reserved Register (neither R nor W)
+Reserved.
+
+Chip versions
+The SCN2681 is manufactured with 24..44 pins, the differences are:
+ 24pin basic cut-down version ;without IP0-1/OP0-1 = without CTS/RTS
+ 28pin additional IP2,OP0,OP1,X2 ;without IP0-1 = without CTS
+ 40pin additional IP0-IP6,OP0-OP7,X2 ;full version
+ 44pin same as 40pin with four NC pins ;full version (SMD)
+Unknown which of them is supposed to be used with the PSX?
+Note: The Motorola 68681 should be the same as the Philips/Signetics 2681.
+
+Notes
+Unknown if the Interrupt signal is connected to the PSX... there seems to be no
+spare IRQ for it, though it <might> share an IRQ with whatever other
+hardware...?
+The BIOS seems to use only one of the two channels; for the std_io functions:
+--> BIOS TTY Console (std_io)
+Aside from the external DUART, the PSX additionally contains an internal UART,
+--> Serial Port (SIO)
+The DTL-H2000 devboard uses a non-serial "ATCONS" channel for TTY stuff,
+--> EXP2 DTL-H2000 I/O Ports
+
+EXP2 DTL-H2000 I/O Ports
+------------------------
+
+The DTL-H2000 contains extended 8Mbyte Main RAM (instead of normal 2Mbyte),
+plus additional 1MByte RAM in Expansion Area at 1FA00000h, plus some I/O ports
+at 1F8020xxh:
+
+1F802000h - DTL-H2000: EXP2: - ATCONS STAT (R)
+ 0 Unknown, used for something
+ 1 Unknown/unused
+ 2 Unknown, used for something
+ 3 TTY/Atcons TX Ready (0=Busy, 1=Ready)
+ 4 TTY/Atcons RX Available (0=None, 1=Yes)
+ 5-7 Unknown/unused
+
+1F802002h - DTL-H2000: EXP2: - ATCONS DATA (R and W)
+ 0-7 TTY/Atcons RX/TX Data
+TTY channel for message output (TX) and debug console keyboard input (RX). The
+DTL-H2000 is using this "ATCONS" stuff instead of the DUART stuff used in
+retail console BIOSes ("CONS" seems to refer to "Console", and "AT" might refer
+to PC/AT or whatever).
+
+1F802004h - DTL-H2000: EXP2: - 16bit - ?
+ 0-15 Data...?
+
+1F802030h - DTL-H2000: Secondary IRQ10 Controller (IRQ Flags)
+This register does expand IRQ10 (Lightgun) to more than one IRQ source. The
+register contains only Secondary IRQ Flags (there seem to be no Secondary IRQ
+Enable bits; at least not for Lightguns).
+ 0 ... used for something
+ 1 Lightgun IRQ (write: 0=No change, 1=Acknowledge) (read: 0=None, 1=IRQ)
+ 2-3 Unknown/unused (write: 0=Normal)
+ 4 ... acknowledged at 1FA00B04h, otherwise unused
+ 5 ... TTY RX ?
+ 6-7 Unknown/unused (write: 0=Normal)
+ 8-31 Not used by DTL-H2000 BIOS (but Lightgun games write 0 to these bits)
+Retail games that support IRQ10-based "Konami" Lightguns are containing code
+for detecting and accessing port 1F802030h. The detection works by examining a
+value in the BIOS ROM like so:
+ IF [BFC00104h]=00002000h then Port 1F802030h does exist (DTL-H2000)
+ IF [BFC00104h]=00002500h then Port 1F802030h does NOT exist
+ IF [BFC00104h]=00000003h then Port 1F802030h does NOT exist (default)
+ IF [BFC00104h]= <other> then Port 1F802030h does NOT exist
+Normal consoles don't include Port 1F802030h, and IRQ10 is wired directly to
+the controller port, and the value at [BFC00104h] is always 00000003h.
+Accordingly, one cannot upgrade the console just by plugging a Secondary IRQ10
+controller to the expansion port (instead, one would need to insert the
+controller between the CPU and controller plug, and to install a BIOS with
+[BFC00104h]=00002000h).
+The DTL-H2000 BIOS accesses 1F802030h with 8bit load/store opcodes, however,
+the Lightgun games use 32bit load/store - which is theoretically overlapping
+port 1F802032h, though maybe the memory system does ignore the upper bits.
+
+1F802032h - DTL-H2000: EXP2: - maybe IRQ enable?
+ 0 Used for something (CLEARED on some occassions)
+ 1-3 Unknown/unused
+ 4 Used for something (SET on some occassions)
+ 5-7 Unknown/unused
+
+1F802040h - DTL-H2000: EXP2: 1-byte - DIP Switch?
+ 0-7 DIP Value (00h..FFh, but should be usually 00h..02h)
+This register selects the DTL-H2000 boot mode, for whatever reason it's called
+"DIP Switch" register, although the DTL-H2000 boards don't seem to contain any
+such DIP Switches (instead, it's probably configured via some I/O ports on PC
+side). Possible values are:
+ DIP=0 --> .. long delay before TTY? with "PSX>" prompt, throws CDROM cmds
+ DIP=1 --> .. long delay before TTY? no "PSX>" prompt PSY-Q?
+ DIP=2 --> .. instant TTY? with "PSX>" prompt
+ DIP=3 --> Lockup
+ DIP=04h..FFh --> Lockup with POST=04h..FFh
+
+1F802042h - DTL-H2000: EXP2: POST/LED (R/W)
+--> EXP2 Post Registers
+
+EXP2 Post Registers
+-------------------
+
+1F802041h - POST - External 7-segment Display (W)
+ 0-3 Current Boot Status (00h..0Fh)
+ 4-7 Not used by BIOS (always set to 0)
+During boot, the BIOS writes incrementing values to this register, allowing to
+display the current boot status on an external 7 segment display (much the same
+as Port 80h used in PC BIOSes).
+
+1F802042h - DTL-H2000: EXP2: POST/LED (R/W)
+ 0-7 Post/LED value
+8bit wide, otherwise same as POST 1F802041h on retail consoles.
+
+1F802070h - POST2 - Unknown? (W) - PS2
+Might be a configuration port, or it's another POST register (which is used
+prior to writing the normal POST bytes to 1FA00000h).
+The first write to 1F802070h is 32bit, all further writes seem to be 8bit.
+
+1FA00000h - POST3 - External 7-segment Display (W) - PS2
+Similar to POST, but PS2 BIOS uses this address.
+
+EXP2 Nocash Emulation Expansion
+-------------------------------
+
+1F802060h Emu-Expansion ID1 "E" (R)
+1F802061h Emu-Expansion ID2 "X" (R)
+1F802062h Emu-Expansion ID3 "P" (R)
+1F802063h Emu-Expansion Version (01h) (R)
+Contains ID and Version.
+
+1F802064h Emu-Expansion Enable1 "O" (R/W)
+1F802065h Emu-Expansion Enable2 "N" (R/W)
+Activates the Halt and Turbo Registers (when set to "ON").
+
+1F802066h Emu-Expansion Halt (R)
+When enabled (see above), doing an 8bit read from this address stops the CPU
+emulation unless/until an Interrupt occurs (when "CAUSE AND SR AND FF00h"
+becomes nonzero). Can be used to reduce power consumption, and to make the
+emulation faster.
+
+1F802067h Emu-Expansion Turbo Mode Flags (R/W)
+When enabled (see above), writing to this register activates/deactivates
+"turbo" mode, which is causing new data to arrive immediately after
+acknowledging the previous interrupt.
+ 0 CDROM Turbo (0=Normal, 1=Turbo)
+ 1 Memory Card Turbo (0=Normal, 1=Turbo)
+ 2 Controller Turbo (0=Normal, 1=Turbo)
+ 3-7 Reserved (must be zero)
+
+Memory Control
+--------------
+
+The Memory Control registers are initialized by the BIOS, and, normally
+software doesn't need to change that settings. Some registers are useful for
+expansion hardware (allowing to increase the memory size and bus width).
+
+1F801000h - Expansion 1 Base Address (usually 1F000000h)
+1F801004h - Expansion 2 Base Address (usually 1F802000h)
+ 0-23 Base Address (Read/Write)
+ 24-31 Fixed (Read only, always 1Fh)
+For Exansion 1, the address is forcefully aligned to the selected expansion
+size (see below), ie. if the size is bigger than 1 byte, then the lower bit(s)
+of the base address are ignored.
+For Expansion 2, trying to use ANY other value than 1F802000h seems to disable
+the Expansion 2 region, rather than mapping it to the specified address (ie.
+Port 1F801004h doesn't seem to work).
+For Expansion 3, the address seems to be fixed (1FA00000h).
+
+1F801008h - Expansion 1 Delay/Size (usually 0013243Fh) (512Kbytes, 8bit bus)
+1F80100Ch - Expansion 3 Delay/Size (usually 00003022h) (1 byte)
+1F801010h - BIOS ROM Delay/Size (usually 0013243Fh) (512Kbytes, 8bit bus)
+1F801014h - SPU Delay/Size (200931E1h) (use 220931E1h for SPU-RAM reads)
+1F801018h - CDROM Delay/Size (00020843h or 00020943h)
+1F80101Ch - Expansion 2 Delay/Size (usually 00070777h) (128 bytes, 8bit bus)
+ 0-3 Unknown (R/W)
+ 4-7 Access Time (00h..0Fh=00h..0Fh Cycles)
+ 8 Use COM0 Time (0=No, 1=Yes, add to Access Time)
+ 9 Use COM1 Time (0=No, 1=Probably Yes, but has no effect?)
+ 10 Use COM2 Time (0=No, 1=Yes, add to Access Time)
+ 11 Use COM3 Time (0=No, 1=Yes, clip to MIN=(COM3+6) or so?)
+ 12 Data Bus-width (0=8bit, 1=16bit)
+ 13-15 Unknown (R/W)
+ 16-20 Memory Window Size (1 SHL N bytes) (0..1Fh = 1 byte ... 2 gigabytes)
+ 21-23 Unknown (always zero)
+ 24-27 Unknown (R/W) ;must be non-zero for SPU-RAM reads
+ 28 Unknown (always zero)
+ 29 Unknown (R/W)
+ 30 Unknown (always zero)
+ 31 Unknown (R/W) (Port 1F801008h only; always zero for other ports)
+Trying to access addresses that exceed the selected size causes an exception.
+Maximum size would be Expansion 1 = 17h (8MB), BIOS = 16h (4MB), Expansion 2 =
+0Dh (8KB), Expansion 3 = 15h (2MB). Trying to select larger sizes would overlap
+the internal I/O ports, and crash the PSX. The Size bits seem to be ignored for
+SPU/CDROM. The SPU timings seem to be applied for both the 200h-byte SPU region
+at 1F801C00h and for the 200h-byte unknown region at 1F801E00h.
+
+1F801020h - COM_DELAY / COMMON_DELAY (00031125h or 0000132Ch or 00001325h)
+ 0-3 COM0 - Offset A ;used for SPU/EXP2 (and for adjusted CDROM timings)
+ 4-7 COM1 - No effect? ;used for EXP2
+ 8-11 COM2 - Offset B ;used for BIOS/EXP1/EXP2
+ 12-15 COM3 - Min Value ;used for CDROM
+ 16-17 COM? - Unknown ;used for whatever
+ 18-31 Unknown/unused (read: always 0000h)
+This register contains clock cycle offsets that can be added to the Access Time
+values in Port 1F801008h..1Ch. Works (somehow) like so:
+ 1ST=0, SEQ=0, MIN=0
+ IF Use_COM0 THEN 1ST=1ST+COM0-1, SEQ=SEQ+COM0-1
+ IF Use_COM2 THEN 1ST=1ST+COM2, SEQ=SEQ+COM2
+ IF Use_COM3 THEN MIN=COM3
+ IF 1ST<6 THEN 1ST=1ST+1 ;(somewhat like so)
+ 1ST=1ST+AccessTime+2, SEQ=SEQ+AccessTime+2
+ IF 1ST<(MIN+6) THEN 1ST=(MIN+6)
+ IF SEQ<(MIN+2) THEN SEQ=(MIN+2)
+The total access time is the sum of First Access, plus any Sequential
+Access(es), eg. for a 32bit access with 8bit bus: Total=1ST+SEQ+SEQ+SEQ.
+If the access is done from code in (uncached) RAM, then 0..4 cycles are added
+to the Total value (the exact number seems to vary depending on the used COMx
+values or so).
+And the purpose... probably allows to define the length of the chipselect
+signals, and of gaps between that signals...?
+
+1F801060h - RAM_SIZE (R/W) (usually 00000B88h) (or 00000888h)
+ 0-2 Unknown (no effect)
+ 3 Crashes when zero (except PU-7 and EARLY-PU-8, which <do> use bit3=0)
+ 4-6 Unknown (no effect)
+ 7 Delay on simultaneous CODE+DATA fetch from RAM (0=None, 1=One Cycle)
+ 8 Unknown (no effect) (should be set for 8MB, cleared for 2MB)
+ 9-11 Define 8MB Memory Window (first 8MB of KUSEG,KSEG0,KSEG1)
+ 12-15 Unknown (no effect)
+ 16-31 Unknown (Garbage)
+Possible values for Bit9-11 are:
+ 0 = 1MB Memory + 7MB Locked
+ 1 = 4MB Memory + 4MB Locked
+ 2 = 1MB Memory + 1MB HighZ + 6MB Locked
+ 3 = 4MB Memory + 4MB HighZ
+ 4 = 2MB Memory + 6MB Locked ;<--- would be correct for PSX
+ 5 = 8MB Memory ;<--- default by BIOS init
+ 6 = 2MB Memory + 2MB HighZ + 4MB Locked ;<-- HighZ = Second /RAS
+ 7 = 8MB Memory
+The BIOS initializes this to setting 5 (8MB) (ie. the 2MB RAM repated 4 times),
+although the "correct" would be setting 4 (2MB, plus other 6MB Locked). The
+remaining memory, after the first 8MB, and up to the Expansion/IO/BIOS region
+seems to be always Locked.
+The HighZ regions are FFh-filled, that even when grounding data lines on the
+system bus (ie. it is NOT a mirror of the PIO expansion region).
+Locked means that the CPU generates an exception when accessing that area.
+Note: Wipeout uses a BIOS function that changes RAM_SIZE to 00000888h (ie. with
+corrected size of 2MB, and with the unknown Bit8 cleared). Gundam Battle
+Assault 2 does actually use the "8MB" space (with stacktop in mirrored RAM at
+807FFFxxh).
+Clearing bit7 causes many games to hang during CDROM loading on both EARLY-PU-8
+and LATE-PU-8 (but works on PU-18 through PM-41).
+
+FFFE0130h Cache Control (R/W)
+ 0-2 Unknown (Read/Write) (R/W)
+ 3 Scratchpad Enable 1 (0=Disable, 1=Enable when Bit7 is set, too) (R/W)
+ 4-5 Unknown (Read/Write) (R/W)
+ 6 Unknown (read=always zero) (R) or (W) or unused..?
+ 7 Scratchpad Enable 2 (0=Disable, 1=Enable when Bit3 is set, too) (R/W)
+ 8 Unknown (R/W)
+ 9 Crash (0=Normal, 1=Crash if code-cache enabled) (R/W)
+ 10 Unknown (read=always zero) (R) or (W) or unused..?
+ 11 Code-Cache Enable (0=Disable, 1=Enable) (R/W)
+ 12-31 Unknown (R/W)
+Used by BIOS to initialize cache (in combination with COP0), like so:
+ Init Cache Step 1:
+ [FFFE0130h]=00000804h, then set cop0_sr=00010000h, then
+ zerofill each FOURTH word at [0000..0FFFh], then set cop0_sr=zero.
+ Init Cache Step 2:
+ [FFFE0130h]=00000800h, then set cop0_sr=00010000h, then
+ zerofill ALL words at [0000h..0FFFh], then set cop0_sr=zero.
+ Finish Initialization:
+ read 8 times 32bit from [A0000000h], then set [FFFE0130h]=0001E988h
+Note: FFFE0130h is described in LSI's "L64360" datasheet, chapter 14 (and
+probably also in their LR33300/LR33310 datasheet, if it were available in
+internet).
+
+Unpredictable Things
+--------------------
+
+Normally, I/O ports should be accessed only at their corresponding size (ie.
+16bit read/write for 16bit ports), and of course, only existing memory and I/O
+addresses should be used. When not recursing that rules, some more or less
+(un-)predictable things may happen...
+
+I/O Write Datasize
+ Address Content W.8bit W.16bit W.32bit
+ 00000000h-00xFFFFFh Main RAM OK OK OK
+ 1F800000h-1F8003FFh Scratchpad OK OK OK
+ 1F801000h-1F801023h MEMCTRL (w32) (w32) OK
+ 1F80104xh JOY_xxx (w16) OK CROP
+ 1F80105xh SIO_xxx (w16) OK CROP
+ 1F801060h-1F801063h RAM_SIZE (w32) (w32) OK (with crash)
+ 1F801070h-1F801077h IRQCTRL (w32) (w32) OK
+ 1F8010x0h-1F8010x3h DMAx.ADDR (w32) (w32) OK
+ 1F8010x4h-1F8010x7h DMAx.LEN OK OK OK
+ 1F8010x8h-1F8010xFh DMAx.CTRL/MIRR (w32) (w32) OK
+ 1F8010F0h-1F8010F7h DMA.DPCR/DICR (w32) (w32) OK
+ 1F8010F8h-1F8010FFh DMA.unknown IGNORE IGNORE IGNORE
+ 1F801100h-1F80110Bh Timer 0 (w32) (w32) OK
+ 1F801110h-1F80111Bh Timer 1 (w32) (w32) OK
+ 1F801120h-1F80112Bh Timer 2 (w32) (w32) OK
+ 1F801800h-1F801803h CDROM OK ? ?
+ 1F801810h-1F801813h GPU.GP0 ? ? OK
+ 1F801814h-1F801817h GPU.GP1 ? ? OK
+ 1F801820h-1F801823h MDEC.CMD/DTA ? ? OK
+ 1F801824h-1F801827h MDEC.CTRL ? ? OK
+ 1F801C00h-1F801E7Fh SPU (i16) OK OK
+ 1F801E80h-1F801FFFh SPU.UNUSED IGNORE IGNORE IGNORE
+ 1F802020h-1F80202Fh DUART OK ? ?
+ 1F802041h POST OK ? ?
+ FFFE0130h-FFFE0133h CACHE.CTRL (i32) (i32) OK
+Whereas,
+ OK works
+ (w32) write full 32bits (left-shifted if address isn't word-aligned)
+ (w16) write full 16bits (left-shifted if address isn't halfword-aligned)
+ (i32) write full 32bits (ignored if address isn't word-aligned)
+ (i16) write full 16bits (ignored if address isn't halfword-aligned)
+ CROP write only lower 16bit (and leave upper 16bit unchanged)
+It's somewhat "legit" to use 16bit writes on 16bit registers like RAM_SIZE,
+I_STAT, I_MASK, and Timer 0-2.
+Non-4-byte aligned 8bit/16bit writes to RAM_SIZE do crash (probably because the
+"(w32)" effect is left-shifting the value, so lower 8bit become zero).
+Results on unaligned I/O port writes (via SWL/SWR opcodes) are unknown.
+
+I/O Read Datasize
+In most cases, I/O ports can be read in 8bit, 16bit, or 32bit units, regardless
+of their size, among others allowing to read two 16bit ports at once with a
+single 32bit read. If there's only one 16bit port within a 32bit region, then
+32bit reads often return garbage in the unused 16bits. Also, 8bit or 16bit VRAM
+data reads via GPUREAD probably won't work? Expansion 2 Region can be accessed
+only via 8bit reads, and 16bit/32bit reads seem to cause exceptions (or rather:
+no such exception!) (except, probably 16bit reads are allowed when the region
+is configured to 16bit databus width).
+There are at least some special cases:
+ FFFE0130h-FFFE0133h 8bit (+16bit?) read works ONLY from word-aligned address
+
+Cache Problems
+The functionality of the Cache is still widely unknown. Not sure if DMA
+transfers are updating or invalidating cache. Cached Data within KSEG0 should
+be automatically also cached at the corresponding mirrored address in KUSEG and
+vice versa. Mirrors within KSEG1 (or within KUSEG) may be a different thing,
+eg. when using addresses spead across the first 8MB region to access the 2MB
+RAM. Same problems may occor for Expansion and BIOS mirrors, although, not sure
+if that regions are cached.
+
+Writebuffer Problems
+The writebuffer seems to be disabled for the normal I/O area at 1F801000h,
+however, it appears to be enabled for the Expansion I/O region at 1F802000h
+(after writing to 1F802041h, the BIOS issues 4 dummy writes to RAM, apparently
+(?) in order to flush the writebuffer). The same might apply for Expansion
+Memory region at 1F000000h, although usually that region would contain ROM, so
+it'd be don't care whether it is write-buffered or not.
+
+CPU Load/Store Problems
+XXcpuREG ---> applies ONLY to LOAD (not to store)
+Memory read/write opcodes take a 1-cycle delay until the data arrives at the
+destination, ie. the next opcode should not use the destination register (or
+more unlikely, the destination memory location) as source operand. Usually,
+when trying to do so, the second opcode would receive the OLD value - however,
+if an exception occurs between the two opcodes, then the read/write operation
+may finish, and the second opcode would probably receive the NEW value.
+
+CPU Register Problems - R1 (AT), R26 (K0), R29 (SP)
+Exception handlers cannot preserve all registers, before returning, they must
+load the return address into a general purpose register (conventionally R26 aka
+K0), so be careful not to use that register, unless you are 100% sure that no
+interrupts and no other exceptions can occur. Some exception handlers might
+also destroy R27 aka K1 (though execption handler in the PSX Kernel leaves that
+register unchanged).
+Some assemblers (not a22i in nocash syntax mode) are internally using R1 aka AT
+as scratch register for some pseudo opcodes, including for a "sw rx,imm32"
+pseudo opcode (which is nearly impossible to separate from the normal "sw
+rx,imm16" opcode), be careful not to use R1, unless you can trust your
+assembler not to destroy that register behind your back.
+The PSX Kernel uses "Full-Decrementing-Wasted-Stack", where "Wasted" means that
+when calling a sub-function with N parameters, then the caller must
+pre-allocate N works on stack, and the sub-function may freely use and destroy
+these words; at [SP+0..N*4-1].
+
+Locked Locations in Memory and I/O Area
+ 00800000h ;-when Main RAM configured to end at 7FFFFFh
+ 1F080000h 780000h ;-when Expansion 1 configured to end at 7FFFFh
+ 1F800400h C00h ;-region after Scratchpad
+ 1F801024h 1Ch ;\
+ 1F801064h 0Ch ;
+ 1F801078h 08h ;
+ 1F801140h 6C0h ; gaps in I/O region
+ 1F801804h 0Ch ;
+ 1F801818h 08h ;
+ 1F801828h 3D8h ;/
+ 1F802080h 3FDF80h ;-when Expansion 2 configured to end at 7Fh
+ 1FC80000h 60380000h ;-when BIOS ROM configured to end at 7FFFFh
+ C0000000h 1FFE0000h ;\
+ FFFE0020h E0h ; gaps in KSEG2 (cache control region)
+ FFFE0140h 1FEC0h ;/
+Trying to access these locations generates an exception. For KSEG0 and KSEG1,
+locked regions are same as for first 512MB of KUSEG.
+
+Mirrors in I/O Area
+ 1F80108Ch+N*10h - D#_CHCR Mirrors - (N=0..6, for DMA channel 0..6)
+Read/writeable mirrors of DMA Control registers at 1F801088h+N*10h.
+
+Garbage Locations in I/O Area
+ 1F801062h (2 bytes) ;\
+ 1F801072h (2 bytes) ; unused addresses in Memory and Interrupt Control area
+ 1F801076h (2 bytes) ;/
+ 1F801102h (2 bytes) ;\
+ 1F801106h (2 bytes) ; unused addresses in Timer 0 area
+ 1F80110Ah (6 bytes) ;/
+ 1F801112h (2 bytes) ;\
+ 1F801116h (2 bytes) ; unused addresses in Timer 1 area
+ 1F80111Ah (6 bytes) ;/
+ 1F801122h (2 bytes) ;\
+ 1F801126h (2 bytes) ; unused addresses in Timer 2 area and next some bytes
+ 1F80112Ah (6 bytes) ;
+ 1F801130h (16 bytes) ;/
+ 1F801820h (4 bytes) ;-read MDEC Data-Out port (if there is no data)
+ FFFE0000h (32 bytes) ;\
+ FFFE0100h (48 bytes) ; unused addresses in Cache control area
+ FFFE0132h (2 bytes) ; (including write-only upper 16bit of Port FFFE0130h)
+ FFFE0134h (12 bytes) ;/
+Unlike all other unused I/O addresses, these addresses are unlocked (ie. they
+do not trigger exceptions on access), however they do not seem to contain
+anything useful. The BIOS never seems to use them. Writing any values to them
+seems to have no effect. And reading acts somewhat unstable:
+Usually returns zeros in most cases. Except that, the first byte on a 10h-byte
+boundary often returns the lower 8bit of the memory address (eg.
+[FFFE0010h]=10h). And, if Code-Cache is disabled via [FFFE0130h].Bit11=0, then
+reading from these registers does return the 32bit opcode that is to be
+executed next (or at some locations, the opcode thereafter).
+Note: Gran Turismo 2 (MagDemo27: GT2\*) reads 16bit from 1F801130h for
+generating a random seed (the game seems to think that there are four (not
+three) hardware timers at 1F8011x0h).
+
+PSX as Abbreviation for Playstation 1
+In gaming and programming scene, "PSX" is most commonly used as abbreviation
+for the original Playstation series (occasionally including PSone). Sony has
+never officially used that abbreviation, however, the Playstation BIOS contains
+the ASCII strings "PSX" and "PS-X" here and there. The letters "PS" are widely
+believed to stand for PlayStation, and the meaning of the "X" is totally
+unknown (although, actually it may stand for POSIX.1, see below).
+
+PSX as Abbreviation for POSIX.1
+According to JMI Software Systems, "PSX" is a trademark of themselves, and
+stands for "single-user, single-group, subset of POSIX.1" (POSIX stands for
+something commonly used by HLL programmers under UNIX or so). That "PSX" kernel
+from JMI is available for various processors, including MIPS processors, and
+like the playstation, it does include functions like "atoi", and does support
+TTY access via Signetics 2681 DUART chips. The DTL-H2000 does also have
+POSIX-style "PSX>" prompt. So, altogether, it's quite possible that Sony has
+licensed the kernel from JMI.
+
+PSX as Abbreviation for an Extended Playstation 2
+As everybody agrees, PSX should be used only as abbreviation for Playstation 1,
+and nobody should never ever use it for the Playstation 2. Well, nobody, except
+Sony... despite of the common use as abbreviation for Playstation 1 (and
+despite of the JMI trademark)... in 2003, Sony has have released a "Playstation
+2 with built-in HDD/DVD Videorecorder" and called that thing "PSX" for the best
+of confusion.
+
+CPU Specifications
+------------------
+
+CPU
+--> CPU Registers
+--> CPU Opcode Encoding
+--> CPU Load/Store Opcodes
+--> CPU ALU Opcodes
+--> CPU Jump Opcodes
+--> CPU Coprocessor Opcodes
+--> CPU Pseudo Opcodes
+
+System Control Coprocessor (COP0)
+--> COP0 - Register Summary
+--> COP0 - Exception Handling
+--> COP0 - Misc
+--> COP0 - Debug Registers
+
+CPU Registers
+-------------
+
+All registers are 32bit wide.
+ Name Alias Common Usage
+ (R0) zero Constant (always 0) (this one isn't a real register)
+ R1 at Assembler temporary (destroyed by some pseudo opcodes!)
+ R2-R3 v0-v1 Subroutine return values, may be changed by subroutines
+ R4-R7 a0-a3 Subroutine arguments, may be changed by subroutines
+ R8-R15 t0-t7 Temporaries, may be changed by subroutines
+ R16-R23 s0-s7 Static variables, must be saved by subs
+ R24-R25 t8-t9 Temporaries, may be changed by subroutines
+ R26-R27 k0-k1 Reserved for kernel (destroyed by some IRQ handlers!)
+ R28 gp Global pointer (rarely used)
+ R29 sp Stack pointer
+ R30 fp(s8) Frame Pointer, or 9th Static variable, must be saved
+ R31 ra Return address (used so by JAL,BLTZAL,BGEZAL opcodes)
+ - pc Program counter
+ - hi,lo Multiply/divide results, may be changed by subroutines
+R0 is always zero.
+R31 can be used as general purpose register, however, some opcodes are using it
+to store the return address: JAL, BLTZAL, BGEZAL. (Note: JALR can optionally
+store the return address in R31, or in R1..R30. Exceptions store the return
+address in cop0r14 - EPC).
+
+R29 (SP) - Full Decrementing Wasted Stack Pointer
+The CPU doesn't explicitly have stack-related registers or opcodes, however,
+conventionally, R29 is used as stack pointer (SP). The stack can be accessed
+with normal load/store opcodes, which do not automatically increase/decrease
+SP, so the SP register must be manually modified to (de-)allocate data.
+The PSX BIOS is using "Full Decrementing Wasted Stack".
+Decrementing means that SP gets decremented when allocating data (that's common
+for most CPUs) - Full means that SP points to the first ALLOCATED word on the
+stack, so the allocated memory is at SP+0 and above, free memory at SP-1 and
+below, Wasted means that when calling a sub-function with N parameters, then
+the caller must pre-allocate N works on stack, and the sub-function may freely
+use and destroy these words; at [SP+0..N*4-1].
+
+For example, "push ra,r16,r17" would be implemented as:
+ sub sp,20h
+ mov [sp+14h],ra
+ mov [sp+18h],r16
+ mov [sp+1Ch],r17
+where the allocated 20h bytes have the following purpose:
+ [sp+00h..0Fh] wasted stack (may, or may not, be used by sub-functions)
+ [sp+10h..13h] 8-byte alignment padding (not used)
+ [sp+14h..1Fh] pushed registers
+
+
+CPU Opcode Encoding
+-------------------
+
+Primary opcode field (Bit 26..31)
+ 00h=SPECIAL 08h=ADDI 10h=COP0 18h=N/A 20h=LB 28h=SB 30h=LWC0 38h=SWC0
+ 01h=BcondZ 09h=ADDIU 11h=COP1 19h=N/A 21h=LH 29h=SH 31h=LWC1 39h=SWC1
+ 02h=J 0Ah=SLTI 12h=COP2 1Ah=N/A 22h=LWL 2Ah=SWL 32h=LWC2 3Ah=SWC2
+ 03h=JAL 0Bh=SLTIU 13h=COP3 1Bh=N/A 23h=LW 2Bh=SW 33h=LWC3 3Bh=SWC3
+ 04h=BEQ 0Ch=ANDI 14h=N/A 1Ch=N/A 24h=LBU 2Ch=N/A 34h=N/A 3Ch=N/A
+ 05h=BNE 0Dh=ORI 15h=N/A 1Dh=N/A 25h=LHU 2Dh=N/A 35h=N/A 3Dh=N/A
+ 06h=BLEZ 0Eh=XORI 16h=N/A 1Eh=N/A 26h=LWR 2Eh=SWR 36h=N/A 3Eh=N/A
+ 07h=BGTZ 0Fh=LUI 17h=N/A 1Fh=N/A 27h=N/A 2Fh=N/A 37h=N/A 3Fh=N/A
+
+Secondary opcode field (Bit 0..5) (when Primary opcode = 00h)
+ 00h=SLL 08h=JR 10h=MFHI 18h=MULT 20h=ADD 28h=N/A 30h=N/A 38h=N/A
+ 01h=N/A 09h=JALR 11h=MTHI 19h=MULTU 21h=ADDU 29h=N/A 31h=N/A 39h=N/A
+ 02h=SRL 0Ah=N/A 12h=MFLO 1Ah=DIV 22h=SUB 2Ah=SLT 32h=N/A 3Ah=N/A
+ 03h=SRA 0Bh=N/A 13h=MTLO 1Bh=DIVU 23h=SUBU 2Bh=SLTU 33h=N/A 3Bh=N/A
+ 04h=SLLV 0Ch=SYSCALL 14h=N/A 1Ch=N/A 24h=AND 2Ch=N/A 34h=N/A 3Ch=N/A
+ 05h=N/A 0Dh=BREAK 15h=N/A 1Dh=N/A 25h=OR 2Dh=N/A 35h=N/A 3Dh=N/A
+ 06h=SRLV 0Eh=N/A 16h=N/A 1Eh=N/A 26h=XOR 2Eh=N/A 36h=N/A 3Eh=N/A
+ 07h=SRAV 0Fh=N/A 17h=N/A 1Fh=N/A 27h=NOR 2Fh=N/A 37h=N/A 3Fh=N/A
+
+Opcode/Parameter Encoding
+ 31..26 |25..21|20..16|15..11|10..6 | 5..0 |
+ 6bit | 5bit | 5bit | 5bit | 5bit | 6bit |
+ -------+------+------+------+------+--------+------------
+ 000000 | N/A | rt | rd | imm5 | 0000xx | shift-imm
+ 000000 | rs | rt | rd | N/A | 0001xx | shift-reg
+ 000000 | rs | N/A | N/A | N/A | 001000 | jr
+ 000000 | rs | N/A | rd | N/A | 001001 | jalr
+ 000000 | <-----comment20bit------> | 00110x | sys/brk
+ 000000 | N/A | N/A | rd | N/A | 0100x0 | mfhi/mflo
+ 000000 | rs | N/A | N/A | N/A | 0100x1 | mthi/mtlo
+ 000000 | rs | rt | N/A | N/A | 0110xx | mul/div
+ 000000 | rs | rt | rd | N/A | 10xxxx | alu-reg
+ 000001 | rs | 00000| <--immediate16bit--> | bltz
+ 000001 | rs | 00001| <--immediate16bit--> | bgez
+ 000001 | rs | 10000| <--immediate16bit--> | bltzal
+ 000001 | rs | 10001| <--immediate16bit--> | bgezal
+ 00001x | <---------immediate26bit---------> | j/jal
+ 00010x | rs | rt | <--immediate16bit--> | beq/bne
+ 00011x | rs | N/A | <--immediate16bit--> | blez/bgtz
+ 001xxx | rs | rt | <--immediate16bit--> | alu-imm
+ 001111 | N/A | rt | <--immediate16bit--> | lui-imm
+ 100xxx | rs | rt | <--immediate16bit--> | load rt,[rs+imm]
+ 101xxx | rs | rt | <--immediate16bit--> | store rt,[rs+imm]
+ x1xxxx | <------coprocessor specific------> | coprocessor (see below)
+
+Coprocessor Opcode/Parameter Encoding
+ 31..26 |25..21|20..16|15..11|10..6 | 5..0 |
+ 6bit | 5bit | 5bit | 5bit | 5bit | 6bit |
+ -------+------+------+------+------+--------+------------
+ 0100nn |0|0000| rt | rd | N/A | 000000 | MFCn rt,rd_dat ;rt = dat
+ 0100nn |0|0010| rt | rd | N/A | 000000 | CFCn rt,rd_cnt ;rt = cnt
+ 0100nn |0|0100| rt | rd | N/A | 000000 | MTCn rt,rd_dat ;dat = rt
+ 0100nn |0|0110| rt | rd | N/A | 000000 | CTCn rt,rd_cnt ;cnt = rt
+ 0100nn |0|1000|00000 | <--immediate16bit--> | BCnF target ;jump if false
+ 0100nn |0|1000|00001 | <--immediate16bit--> | BCnT target ;jump if true
+ 0100nn |1| <--------immediate25bit--------> | COPn imm25
+ 010000 |1|0000| N/A | N/A | N/A | 000001 | COP0 01h ;=TLBR
+ 010000 |1|0000| N/A | N/A | N/A | 000010 | COP0 02h ;=TLBWI
+ 010000 |1|0000| N/A | N/A | N/A | 000110 | COP0 06h ;=TLBWR
+ 010000 |1|0000| N/A | N/A | N/A | 001000 | COP0 08h ;=TLBP
+ 010000 |1|0000| N/A | N/A | N/A | 010000 | COP0 10h ;=RFE
+ 1100nn | rs | rt | <--immediate16bit--> | LWCn rt_dat,[rs+imm]
+ 1110nn | rs | rt | <--immediate16bit--> | SWCn rt_dat,[rs+imm]
+
+Illegal Opcodes
+All opcodes that are marked as "N/A" in the Primary and Secondary opcode tables
+are causing a Reserved Instruction Exception (excode=0Ah).
+The unused operand bits (eg. Bit21-25 for LUI opcode) should be usually zero,
+but do not necessarily trigger exceptions if set to nonzero values.
+
+CPU Load/Store Opcodes
+----------------------
+
+Load instructions
+ movbs rt,[imm+rs] lb rt,imm(rs) rt=[imm+rs] ;byte sign-extended
+ movb rt,[imm+rs] lbu rt,imm(rs) rt=[imm+rs] ;byte zero-extended
+ movhs rt,[imm+rs] lh rt,imm(rs) rt=[imm+rs] ;halfword sign-extended
+ movh rt,[imm+rs] lhu rt,imm(rs) rt=[imm+rs] ;halfword zero-extended
+ mov rt,[imm+rs] lw rt,imm(rs) rt=[imm+rs] ;word
+Load instructions can read from the data cache (if the data is not in the
+cache, or if the memory region is uncached, then the CPU gets halted until it
+has read the data) (however, the PSX doesn't have a data cache).
+
+Caution - Load Delay
+The loaded data is NOT available to the next opcode, ie. the target register
+isn't updated until the next opcode has completed. So, if the next opcode tries
+to read from the load destination register, then it would (usually) receive the
+OLD value of that register (unless an IRQ occurs between the load and next
+opcode, in that case the load would complete during IRQ handling, and so, the
+next opcode would receive the NEW value).
+
+Store instructions
+ movb [imm+rs],rt sb rt,imm(rs) [imm+rs]=(rt AND FFh) ;store 8bit
+ movh [imm+rs],rt sh rt,imm(rs) [imm+rs]=(rt AND FFFFh) ;store 16bit
+ mov [imm+rs],rt sw rt,imm(rs) [imm+rs]=rt ;store 32bit
+Store operations are passed to the write-buffer, so they can execute within a
+single clock cycle (unless the write-buffer was full, in that case the CPU gets
+halted until there's room in the buffer). But, the PSX doesn't have a
+writebuffer...?
+
+Load/Store Alignment
+Halfword addresses must be aligned by 2, word addresses must be aligned by 4,
+trying to access mis-aligned addresses will cause an exception. There's no
+alignment restriction for bytes.
+
+Unaligned Load/Store
+ lwr rt,imm(rs) load right bits of rt from memory (usually imm+0)
+ lwl rt,imm(rs) load left bits of rt from memory (usually imm+3)
+ swr rt,imm(rs) store right bits of rt to memory (usually imm+0)
+ swl rt,imm(rs) store left bits of rt to memory (usually imm+3)
+There's no delay required between lwl and lwr, so you can use them directly
+following eachother, eg. to load a word anywhere in memory without regard to
+alignment:
+ lwl r2,$0003(t0) ;\no delay required between these
+ lwr r2,$0000(t0) ;/(although both access r2)
+ nop ;-requires load delay HERE (before reading from r2)
+ and r2,r2,0ffffh ;-access r2 (eg. reducing it to unaligned 16bit data)
+
+Unaligned Load/Store (Details)
+LWR/SWR transfers the right (=lower) bits of Rt, up-to 32bit memory boundary:
+ lwr/swr [N*4+0] transfer whole 32bit of Rt to/from [N*4+0..3]
+ lwr/swr [N*4+1] transfer lower 24bit of Rt to/from [N*4+1..3]
+ lwr/swr [N*4+2] transfer lower 16bit of Rt to/from [N*4+2..3]
+ lwr/swr [N*4+3] transfer lower 8bit of Rt to/from [N*4+3]
+LWL/SWL transfers the left (=upper) bits of Rt, down-to 32bit memory boundary:
+ lwl/swl [N*4+0] transfer upper 8bit of Rt to/from [N*4+0]
+ lwl/swl [N*4+1] transfer upper 16bit of Rt to/from [N*4+0..1]
+ lwl/swl [N*4+2] transfer upper 24bit of Rt to/from [N*4+0..2]
+ lwl/swl [N*4+3] transfer whole 32bit of Rt to/from [N*4+0..3]
+The CPU has four separate byte-access signals, so, within a 32bit location, it
+can transfer all fragments of Rt at once (including for odd 24bit amounts). The
+transferred data is not zero- or sign-expanded, eg. when transferring 8bit
+data, the other 24bit of Rt and [mem] will remain intact.
+
+Note: The aligned variant can also misused for blocking memory access on
+aligned addresses (in that case, if the address is known to be aligned, only
+one of the opcodes are needed, either LWL or LWR).... Uhhhhhhhm, OR is that NOT
+allowed... more PROBABLY that doesn't work?
+
+CPU ALU Opcodes
+---------------
+
+arithmetic instructions
+ addt rd,rs,rt add rd,rs,rt rd=rs+rt (with overflow trap)
+ add rd,rs,rt addu rd,rs,rt rd=rs+rt
+ subt rd,rs,rt sub rd,rs,rt rd=rs-rt (with overflow trap)
+ sub rd,rs,rt subu rd,rs,rt rd=rs-rt
+ addt rt,rs,imm addi rt,rs,imm rt=rs+(-8000h..+7FFFh) (with ov.trap)
+ add rt,rs,imm addiu rt,rs,imm rt=rs+(-8000h..+7FFFh)
+The opcodes "with overflow trap" do trigger an exception (and leave rd
+unchanged) in case of overflows.
+
+comparison instructions
+ setlt slt rd,rs,rt if rs<rt then rd=1 else rd=0 (signed)
+ setb sltu rd,rs,rt if rs<rt then rd=1 else rd=0 (unsigned)
+ setlt slti rt,rs,imm if rs<(-8000h..+7FFFh) then rt=1 else rt=0 (signed)
+ setb sltiu rt,rs,imm if rs<(FFFF8000h..7FFFh) then rt=1 else rt=0(unsigned)
+
+logical instructions
+ and rd,rs,rt and rd,rs,rt rd = rs AND rt
+ or rd,rs,rt or rd,rs,rt rd = rs OR rt
+ xor rd,rs,rt xor rd,rs,rt rd = rs XOR rt
+ nor rd,rs,rt nor rd,rs,rt rd = FFFFFFFFh XOR (rs OR rt)
+ and rt,rs,imm andi rt,rs,imm rt = rs AND (0000h..FFFFh)
+ or rt,rs,imm ori rt,rs,imm rt = rs OR (0000h..FFFFh)
+ xor rt,rs,imm xori rt,rs,imm rt = rs XOR (0000h..FFFFh)
+
+shifting instructions
+ shl rd,rt,rs sllv rd,rt,rs rd = rt SHL (rs AND 1Fh)
+ shr rd,rt,rs srlv rd,rt,rs rd = rt SHR (rs AND 1Fh)
+ sar rd,rt,rs srav rd,rt,rs rd = rt SAR (rs AND 1Fh)
+ shl rd,rt,imm sll rd,rt,imm rd = rt SHL (00h..1Fh)
+ shr rd,rt,imm srl rd,rt,imm rd = rt SHR (00h..1Fh)
+ sar rd,rt,imm sra rd,rt,imm rd = rt SAR (00h..1Fh)
+ mov rt,i*10000h lui rt,imm rt = (0000h..FFFFh) SHL 16
+Unlike many other opcodes, shifts use 'rt' as second (not third) operand.
+The hardware does NOT generate exceptions on SHL overflows.
+
+Multiply/divide
+ smul rs,rt mult rs,rt hi:lo = rs*rt (signed)
+ umul rs,rt multu rs,rt hi:lo = rs*rt (unsigned)
+ sdiv rs,rt div rs,rt lo = rs/rt, hi=rs mod rt (signed)
+ udiv rs,rt divu rs,rt lo = rs/rt, hi=rs mod rt (unsigned)
+ mov rd,hi mfhi rd rd=hi ;move from hi
+ mov rd,lo mflo rd rd=lo ;move from lo
+ mov hi,rs mthi rs hi=rs ;move to hi
+ mov lo,rs mtlo rs lo=rs ;move to lo
+The mul/div opcodes are starting the multiply/divide operation, starting takes
+only a single clock cycle, however, trying to read the result from the hi/lo
+registers while the mul/div operation is busy will halt the CPU until the
+mul/div has completed. For multiply, the execution time depends on rs (ie.
+"small*large" can be much faster than "large*small").
+ __umul_execution_time_____________________________________________________
+ Fast (6 cycles) rs = 00000000h..000007FFh
+ Med (9 cycles) rs = 00000800h..000FFFFFh
+ Slow (13 cycles) rs = 00100000h..FFFFFFFFh
+ __smul_execution_time_____________________________________________________
+ Fast (6 cycles) rs = 00000000h..000007FFh, or rs = FFFFF800h..FFFFFFFFh
+ Med (9 cycles) rs = 00000800h..000FFFFFh, or rs = FFF00000h..FFFFF801h
+ Slow (13 cycles) rs = 00100000h..7FFFFFFFh, or rs = 80000000h..FFF00001h
+ __udiv/sdiv_execution_time________________________________________________
+ Fixed (36 cycles) no matter of rs and rt values
+For example, when executing "umul 123h,12345678h" and "mov r1,lo", one can
+insert up to six (cached) ALU opcodes, or read one value from PSX Main RAM
+(which has 6 cycle access time) between the "umul" and "mov" opcodes without
+additional slowdown.
+The hardware does NOT generate exceptions on divide overflows, instead, divide
+errors are returning the following values:
+ Opcode Rs Rd Hi/Remainder Lo/Result
+ udiv 0..FFFFFFFFh 0 --> Rs FFFFFFFFh
+ sdiv 0..+7FFFFFFFh 0 --> Rs -1
+ sdiv -80000000h..-1 0 --> Rs +1
+ sdiv -80000000h -1 --> 0 -80000000h
+For udiv, the result is more or less correct (as close to infinite as
+possible). For sdiv, the results are total garbage (about farthest away from
+the desired result as possible).
+Note: After accessing the lo/hi registers, there seems to be a strange rule
+that one should not touch the lo/hi registers in the next 2 cycles or so... not
+yet understood if/when/how that rule applies...?
+
+CPU Jump Opcodes
+----------------
+
+jumps and branches
+Note that the instruction following the branch will always be executed.
+ jmp dest j dest pc=(pc and F0000000h)+(imm26bit*4)
+ call dest jal dest pc=(pc and F0000000h)+(imm26bit*4),ra=$+8
+ jmp rs jr rs pc=rs
+ call rs,ret=rd jalr (rd,)rs(,rd) pc=rs, rd=$+8 ;see caution
+ je rs,rt,dest beq rs,rt,dest if rs=rt then pc=$+4+(-8000h..+7FFFh)*4
+ jne rs,rt,dest bne rs,rt,dest if rs<>rt then pc=$+4+(-8000h..+7FFFh)*4
+ js rs,dest bltz rs,dest if rs<0 then pc=$+4+(-8000h..+7FFFh)*4
+ jns rs,dest bgez rs,dest if rs>=0 then pc=$+4+(-8000h..+7FFFh)*4
+ jgtz rs,dest bgtz rs,dest if rs>0 then pc=$+4+(-8000h..+7FFFh)*4
+ jlez rs,dest blez rs,dest if rs<=0 then pc=$+4+(-8000h..+7FFFh)*4
+ calls rs,dest bltzal rs,dest if rs<0 then pc=$+4+(..)*4, ra=$+8
+ callns rs,dest bgezal rs,dest if rs>=0 then pc=$+4+(..)*4, ra=$+8
+
+JALR cautions
+Caution: The JALR source code syntax varies (IDT79R3041 specs say "jalr rs,rd",
+but MIPS32 specs say "jalr rd,rs"). Moreover, JALR may not use the same
+register for both operands (eg. "jalr r31,r31") (doing so would destroy the
+target address; which is normally no problem, but it can be a problem if an IRQ
+occurs between the JALR opcode and the following branch delay opcode; in that
+case BD gets set, and EPC points "back" to the JALR opcode, so JALR is executed
+twice, with destroyed target address in second execution).
+
+exception opcodes
+Unlike for jump/branch opcodes, exception opcodes are immediately executed (ie.
+without executing the following opcode).
+ syscall imm20 generates a system call exception
+ break imm20 generates a breakpoint exception
+The 20bit immediate doesn't affect the CPU (however, the exception handler may
+interprete it by software; by examing the opcode bits at [epc-4]).
+
+CPU Coprocessor Opcodes
+-----------------------
+
+Coprocessor Instructions (COP0..COP3)
+ mov rt,cop#Rd(0-31) mfc# rt,rd ;rt = cop#datRd ;data regs
+ mov rt,cop#Rd(32-63) cfc# rt,rd ;rt = cop#cntRd ;control regs
+ mov cop#Rd(0-31),rt mtc# rt,rd ;cop#datRd = rt ;data regs
+ mov cop#Rd(32-63),rt ctc# rt,rd ;cop#cntRd = rt ;control regs
+ mov cop#cmd,imm25 cop# imm25 ;exec cop# command 0..1FFFFFFh
+ mov cop#Rt(0-31),[rs+imm] lwc# rt,imm(rs) ;cop#dat_rt = [rs+imm] ;word
+ mov [rs+imm],cop#Rt(0-31) swc# rt,imm(rs) ;[rs+imm] = cop#dat_rt ;word
+ jf cop#flg,dest bc#f dest ;if cop#flg=false then pc=$+disp
+ jt cop#flg,dest bc#t dest ;if cop#flg=true then pc=$+disp
+ rfe rfe ;return from exception (COP0)
+ tlb<xx> tlb<xx> ;virtual memory related (COP0)
+Unknown if any tlb-opcodes (tlbr,tlbwi,tlbwr,tlbp) are implemented in the psx?
+
+Caution - Load Delay
+When reading from a coprocessor register, the next opcode cannot use the
+destination register as operand (much the same as the Load Delays that occur
+when reading from memory; see there for details).
+Reportedly, the Load Delay applies for the next TWO opcodes after coprocessor
+reads, but, that seems to be nonsense (the PSX does finish both COP0 and COP2
+reads after ONE opcode).
+
+Caution - Store Delay
+In some cases, a similar delay occurs when writing to a coprocessor register.
+COP0 is more or less free of store delays (eg. one can read from a cop0
+register immediately after writing to it), the only known exception is the cop2
+enable bit in cop0r12.bit30 (setting that cop0 bit acts delayed, and cop2 isn't
+actually enabled until after 2 clock cycles or so).
+Writing to cop2 registers has a delay of 2..3 clock cycles. In most cases, that
+is probably (?) only 2 cycles, but special cases like writing to IRGB (which
+does additionally affect IR1,IR2,IR3) take 3 cycles until the result arrives in
+all registers).
+Note that Store Delays are counted in numbers of clock cycles (not in numbers
+of opcodes). For 3 cycle delay, one must usually insert 3 cached opcodes (or
+one uncached opcode).
+
+CPU Pseudo Opcodes
+------------------
+
+Pseudo instructions (native/spasm)
+ nop ;alias for sll r0,r0,0
+ move rd,rs ;alias for addu rd,rs,r0
+ la rx,imm32 ;load address (alias for lui rx / addiu rx)
+ li rx,imm32 ;load immediate (alias for lui rx / ori rx)
+ li rx,imm16 ;load immediate (alias for ori, range 0..FFFFh)
+ li rx,-imm15 ;load immediate (alias for addiu, range -1..-8000h)
+ li rx,imm16*10000h ;load immediate (alias for lui)
+ lw rx,imm32 ;load from address (lui rx / lw rx,rx)
+ sw rx,imm32 ;store to address (lui r1 / sw rx,r1) (destroys r1!)
+ lb,lh,lwl,lwr,lbu,lhu;as above pseudo lw
+ sb,sh,swl,swr ;as above pseudo sw (ie. also destroys r1!)
+ alu rx,op ;alias for alu rx,rx,op
+ alu(u) rx,rx,imm ;alias for alui(u) rx,rx,imm
+ jalr rx ;alias for jalr (RA,)rx(,RA)
+ subi(u) rt,rs,imm ;alias for addi(u) rt,rs,-imm
+ beqz rx,dest ;alias for beq rx,r0,dest
+ bnez rx,dest ;alias for bne rx,r0,dest
+ b dest ;alias for beq r0,r0,dest (jump relative/spasm)
+ bra dest ;alias for ...? (jump relative/gnu)
+ bal dest ;alias for ...? (call relative/spasm)
+
+Pseudo instructions (nocash/a22i)
+ mov rx,NNNN0000h ;alias for lui rx,NNNNh
+ mov rx,0000NNNNh ;alias for or rx,r0,NNNNh ;max +FFFFh
+ mov rx,-imm15 ;alias for add rx,r0,-NNNNh ;min -8000h
+ mov rx,ry ;alias for or rx,ry,0 (or "addiu")
+ nop ;alias for shl r0,r0,0
+ jrel dest ;alias for blez R0,dest ;relative jump
+ crel dest ;alias for callns R0,dest ;relative call
+ jz rx,dest ;alias for je rx,R0,dest
+ jnz rx,dest ;alias for jne rx,R0,dest
+ call rx ;alias for call rx,ret=RA
+ ret ;alias for jmp ra
+ subt rt,rs,imm ;alias for addt rt,rs,-imm
+ sub rt,rs,imm ;alias for add rt,rs,-imm
+ alu rx,op ;alias for alu rx,rx,op
+ neg(t) rx,ry ;alias for sub(t) rx,R0,ry
+ not rx,ry ;alias for nor rx,R0,ry
+ neg(t)/not rx ;alias for neg(t)/not rx,rx
+ setz rx,ry ;alias for setb rx,ry,1 (set if zero)
+ setnz rx,ry ;alias for setb rx,R0,ry (set if nonzero)
+ syscall/break ;alias for syscall/break 000000h
+Below are pseudo instructions combined of two 32bit opcodes...
+ movp rx,imm32 ;alias for lui rx,imm16 -plus- ori rx,rx,imm16)
+ movpa rx,imm32 ;alias for lui rx,imm16 -plus- addiu rx,rx,imm16)
+ mov(bhs)p rx,[imm32] ;load from address (lui rx,imm16 / mov rx,[rx+imm16])
+ movu [rs+imm] ;alias for lwr/swr [rs+imm] plus lwl/swl [rs+imm+3]
+ reti ;alias for jmp k0 plus rfe
+Below are pseudo instructions combined of two or more 32bit opcodes...
+ push rlist ;alias for sub sp,n*4 -- mov [sp+(1..n)*4],r1..rn
+ pop rlist ;alias for mov r1..rn,[sp+(1..n)*4] -- add sp,n*4
+ pop pc,rlist ;alias for pop ra,rlist -- jmp ra
+
+Possible more Pseudos...
+ call x0000000h ;call y0000000h (could be half-working for mem mirrors?)
+ setae,setge ;--> setb,setlt with swapped operands
+
+Directives (nocash)
+ .mips ;select MIPS instruction set (alternately .hc05 for MC68HC05)
+ .bios ;create a .ROM file (instead of .EXE)
+ .auto_nop ;append NOPs to jumps ;unless next opcode starts with a +
+ org imm ;assume following code to be originated at address "imm"
+ db n(,n(..))) ;define 8bit data values(s) or quoted ASCII strings
+ dw n(,n(..))) ;define 16bit data values(s) (not 32bit data!)
+ dd n(,n(..))) ;define 32bit data values(s)
+ .align imm
+ 0 ;alias for immediate 0 and register R0 (whichever fits)
+
+Directives (native)
+ org imm ;self-explaining (but, default=$80010000 for spasm!)
+ align imm ;self-explaining (probably zeropadded?)
+ db n(,n(..))) ;define 8bit data values(s) or quoted ASCII strings
+ dh n(,n(..))) ;define 16bit data values(s)
+ dw n(,n(..))) ;define 32bit data values(s) (not 16bit data!)
+ dcb len,value ;fill <len> bytes by <value> (different as DCB on ARM CPUs)
+ xyz ;define label "xyz" at current address (without colon)
+ xyz equ n ;assign value n to xyz
+ xyz = n ;probably same/sililar as "equ"
+ ;xyz ;comments invoked with semicolon (spasm)
+ incbin file.bin ;import binary file
+ include file.asm ;import asm file
+ zero ;alias for r0
+ >imm32 ;alias for (i-(i AND 8000h))/10000h, and/or i/10000h ?
+ <imm32 ;alias for (i AND 0FFFFh), used for SW(+/-) and ORI(+)?
+ end ;N/A ;no "end" or ".end" directive needed/used by spasm
+ r1 aka at ;N/A ;some assemblers may (optionally) reject to use r1/at
+
+Syntax for unknown assembler (for pad.s)
+It uses "0x" for HEX values (but doesn't use "$" for registers).
+It uses "#" instead of ";" for comments.
+It uses ":" for labels (fortunately).
+The assembler has at least one directive: ".byte" (equivalent to "db" on other
+assemblers).
+I've no clue which assembler is used for that syntax... could that be the Psy-Q
+assembler?
+
+COP0 - Register Summary
+-----------------------
+
+COP0 Register Summary
+ cop0r0-r2 - N/A
+ cop0r3 - BPC - Breakpoint on execute (R/W)
+ cop0r4 - N/A
+ cop0r5 - BDA - Breakpoint on data access (R/W)
+ cop0r6 - JUMPDEST - Randomly memorized jump address (R)
+ cop0r7 - DCIC - Breakpoint control (R/W)
+ cop0r8 - BadVaddr - Bad Virtual Address (R)
+ cop0r9 - BDAM - Data Access breakpoint mask (R/W)
+ cop0r10 - N/A
+ cop0r11 - BPCM - Execute breakpoint mask (R/W)
+ cop0r12 - SR - System status register (R/W)
+ cop0r13 - CAUSE - (R) Describes the most recently recognised exception
+ cop0r14 - EPC - Return Address from Trap (R)
+ cop0r15 - PRID - Processor ID (R)
+ cop0r16-r31 - Garbage
+ cop0r32-r63 - N/A - None such (Control regs)
+
+COP0 - Exception Handling
+-------------------------
+
+cop0r13 - CAUSE - (Read-only, except, Bit8-9 are R/W)
+Describes the most recently recognised exception
+ 0-1 - Not used (zero)
+ 2-6 Excode Describes what kind of exception occured:
+ 00h INT Interrupt
+ 01h MOD Tlb modification (none such in PSX)
+ 02h TLBL Tlb load (none such in PSX)
+ 03h TLBS Tlb store (none such in PSX)
+ 04h AdEL Address error, Data load or Instruction fetch
+ 05h AdES Address error, Data store
+ The address errors occur when attempting to read
+ outside of KUseg in user mode and when the address
+ is misaligned. (See also: BadVaddr register)
+ 06h IBE Bus error on Instruction fetch
+ 07h DBE Bus error on Data load/store
+ 08h Syscall Generated unconditionally by syscall instruction
+ 09h BP Breakpoint - break instruction
+ 0Ah RI Reserved instruction
+ 0Bh CpU Coprocessor unusable
+ 0Ch Ov Arithmetic overflow
+ 0Dh-1Fh Not used
+ 7 - Not used (zero)
+ 8-15 Ip Interrupt pending field. Bit 8 and 9 are R/W, and
+ contain the last value written to them. As long
+ as any of the bits are set they will cause an
+ interrupt if the corresponding bit is set in IM.
+ 16-27 - Not used (zero)
+ 28-29 CE Contains the coprocessor number if the exception
+ occurred because of a coprocessor instruction for
+ a coprocessor which wasn't enabled in SR.
+ 30 - Not used (zero)
+ 31 BD Is set when last exception points to the
+ branch instruction instead of the instruction
+ in the branch delay slot, where the exception
+ occurred.
+
+cop0r12 - SR - System status register (R/W)
+ 0 IEc Current Interrupt Enable (0=Disable, 1=Enable) ;rfe pops IUp here
+ 1 KUc Current Kernal/User Mode (0=Kernel, 1=User) ;rfe pops KUp here
+ 2 IEp Previous Interrupt Disable ;rfe pops IUo here
+ 3 KUp Previous Kernal/User Mode ;rfe pops KUo here
+ 4 IEo Old Interrupt Disable ;left unchanged by rfe
+ 5 KUo Old Kernal/User Mode ;left unchanged by rfe
+ 6-7 - Not used (zero)
+ 8-15 Im 8 bit interrupt mask fields. When set the corresponding
+ interrupts are allowed to cause an exception.
+ 16 Isc Isolate Cache (0=No, 1=Isolate)
+ When isolated, all load and store operations are targetted
+ to the Data cache, and never the main memory.
+ (Used by PSX Kernel, in combination with Port FFFE0130h)
+ 17 Swc Swapped cache mode (0=Normal, 1=Swapped)
+ Instruction cache will act as Data cache and vice versa.
+ Use only with Isc to access & invalidate Instr. cache entries.
+ (Not used by PSX Kernel)
+ 18 PZ When set cache parity bits are written as 0.
+ 19 CM Shows the result of the last load operation with the D-cache
+ isolated. It gets set if the cache really contained data
+ for the addressed memory location.
+ 20 PE Cache parity error (Does not cause exception)
+ 21 TS TLB shutdown. Gets set if a programm address simultaneously
+ matches 2 TLB entries.
+ (initial value on reset allows to detect extended CPU version?)
+ 22 BEV Boot exception vectors in RAM/ROM (0=RAM/KSEG0, 1=ROM/KSEG1)
+ 23-24 - Not used (zero)
+ 25 RE Reverse endianness (0=Normal endianness, 1=Reverse endianness)
+ Reverses the byte order in which data is stored in
+ memory. (lo-hi -> hi-lo)
+ (Has affect only to User mode, not to Kernel mode) (?)
+ (The bit doesn't exist in PSX ?)
+ 26-27 - Not used (zero)
+ 28 CU0 COP0 Enable (0=Enable only in Kernal Mode, 1=Kernal and User Mode)
+ 29 CU1 COP1 Enable (0=Disable, 1=Enable) (none such in PSX)
+ 30 CU2 COP2 Enable (0=Disable, 1=Enable) (GTE in PSX)
+ 31 CU3 COP3 Enable (0=Disable, 1=Enable) (none such in PSX)
+
+cop0r14 - EPC - Return Address from Trap (R)
+ 0-31 Return Address from Exception
+This address is the instruction at which the exception took place, unless BD is
+set in CAUSE, then the instruction was at EPC+4.
+Interrupts should always return to EPC+0, no matter of the BD flag. That way,
+if BD=1, the branch gets executed again, that's required because EPC stores
+only the current program counter, but not additionally the branch destination
+address.
+Other exceptions may require to handle BD. In simple cases, when BD=0, the
+exception handler may return to EPC+0 (retry execution of the opcode), or to
+EPC+4 (skip the opcode that caused the exception). Note that jumps to faulty
+memory locations are executed without exception, but will trigger address
+errors and bus errors at the target location, ie. EPC (and BadVAddr, in case of
+address errors) point to the faulty address, not to the opcode that has jumped
+to that address).
+
+Interrupts vs GTE Commands
+If an interrupt occurs "on" a GTE command (cop2cmd), then the GTE command is
+executed, but nethertheless, the return address in EPC points to the GTE
+command. So, if the exception handler would return to EPC as usually, then the
+GTE command would be executed twice. In best case, this would be a waste of
+clock cycles, in worst case it may lead to faulty result (if the results from
+the 1st execution are re-used as incoming parameters in the 2nd execution). To
+fix the problem, the exception handler must do:
+ if (cause AND 7Ch)=00h ;if excode=interrupt
+ if ([epc] AND FE000000h)=4A000000h ;and opcode=cop2cmd
+ epc=epc+4 ;then skip that opcode
+Note: The above exception handling is working only in newer PSX BIOSes, but in
+very old PSX BIOSes, it is only incompletely implemented (see "BIOS Patches"
+chapter for common workarounds; or write your own exception handler without
+using the BIOS).
+Of course, the above exeption handling won't work in branch delays (where BD
+gets set to indicate that EPC was modified) (best workaround is not to use GTE
+commands in branch delays).
+
+cop0cmd=10h - RFE opcode - Prepare Return from Exception
+The RFE opcode moves some bits in cop0r12 (SR): bit2-3 are copied to bit0-1,
+and bit4-5 are copied to bit2-3, all other bits (including bit4-5) are left
+unchanged.
+The RFE opcode does NOT automatically jump to EPC. Instead, the exception
+handler must copy EPC into a register (usually R26 aka K0), and then jump to
+that address. Because of branch delays, that would look like so:
+ mov k0,epc ;get return address
+ push k0 ;save epc in memory (if you expect nested exceptions)
+ ... ;whatever (ie. process CAUSE)
+ pop k0 ;restore from memory (if you expect nested exceptions)
+ jmp k0 ;jump to K0 (after executing the next opcode)
+ +rfe ;move SR bit4/5 --> bit2/3 --> bit0/1
+If you expect exceptions to be nested deeply, also push/pop SR. Note that
+there's no way to leave all registers intact (ie. above code destroys K0).
+
+cop0r8 - BadVaddr - Bad Virtual Address (R)
+Contains the address whose reference caused an exception. Set on any MMU type
+of exceptions, on references outside of kuseg (in User mode) and on any
+misaligned reference. BadVaddr is updated ONLY by Address errors (Excode 04h
+and 05h), all other exceptions (including bus errors) leave BadVaddr unchanged.
+
+Exception Vectors (depending on BEV bit in SR register)
+ Exception BEV=0 BEV=1
+ Reset BFC00000h BFC00000h (Reset)
+ UTLB Miss 80000000h BFC00100h (Virtual memory, none such in PSX)
+ COP0 Break 80000040h BFC00140h (Debug Break)
+ General 80000080h BFC00180h (General Interrupts & Exceptions)
+Note: Changing vectors at 800000xxh (kseg0) seems to be automatically reflected
+to the instruction cache without needing to flush cache (at least it worked
+SOMETIMES in my test proggy... but NOT always? ...anyways, it'd be highly
+recommended to flush cache when changing any opcodes), whilst changing mirrors
+at 000000xxh (kuseg) seems to require to flush cache.
+The PSX uses only the BEV=0 vectors (aside from the reset vector, the PSX BIOS
+ROM doesn't contain any of the BEV=1 vectors).
+
+Exception Priority
+ Reset At any time (highest) ;-reset
+ AdEL Memory (Load instruction) ;\
+ AdES Memory (Store instruction) ; memory (data load/store)
+ DBE Memory (Load or store) ;/
+ MOD ALU (Data TLB) ;\
+ TLBL ALU (DTLB Miss) ; none such
+ TLBS ALU (DTLB Miss) ;/
+ Ovf ALU ;-overflow
+ Int ALU ;-interrupt
+ Sys RD (Instruction Decode) ;\
+ Bp RD (Instruction Decode) ;
+ RI RD (Instruction Decode) ;
+ CpU RD (Instruction Decode) ;/
+ TLBL I-Fetch (ITLB Miss) ;-none such
+ AdEL IVA (Instruction Virtual Address) ;\memory (opcode fetch)
+ IBE RD (end of I-Fetch, lowest) ;/
+
+COP0 - Misc
+-----------
+
+cop0r15 - PRID - Processor ID (R)
+ 0-7 Revision
+ 8-15 Implementation
+ 16-31 Not used
+PRID=00000001h on Playstation with CPU CXD8530BQ/CXD8530CQ
+PRID=00000002h on Playstation with CPU CXD8606CQ
+
+cop0r6 - JUMPDEST - Randomly memorized jump address (R)
+The is a rather strange totally useless register. After certain exceptions, the
+CPU does memorize a jump destination address in the register. Once when it has
+memorized an address, the register becomes locked, and the memorized value
+won't change until it becomes unlocked by a new exception. Exceptions that do
+unlock the register are Reset and Interrupts (cause.bit10). Exceptions that do
+NOT unlock the register are syscall/break opcodes, and software generated
+interrupts (eg. cause.bit8).
+In the unlocked state, the CPU does more or less randomly memorize one of the
+next some jump destinations - eg. the destination from the second jump after
+reset, or from a jump that occured immediately before executing the IRQ
+handler, or from a jump inside of the IRQ handler, or even from a later jump
+that occurs shortly after returning from the IRQ handler.
+The register seems to be read-only (although the Kernel initialization code
+writes 0 to it for whatever reason).
+
+cop0r0..r2, cop0r4, cop0r10, cop0r32..r63 - N/A
+Registers 0,1,2,4,10 control virtual memory on some MIPS processors (but
+there's none such in the PSX), and Registers 32..63 (aka "control registers")
+aren't used in any MIPS processors. Trying to read any of these registers
+causes a Reserved Instruction Exception (excode=0Ah).
+
+cop0cmd=01h,02h,06h,08h - TLBR,TLBWI,TLBWR,TLBP
+The PSX supports only one cop0cmd (cop0cmd=10h aka RFE). Trying to execute the
+TLBxx opcodes causes a Reserved Instruction Exception (excode=0Ah).
+
+jf/jt cop0flg,dest - conditional cop0 jumps
+mov [mem],cop0reg / mov cop0reg,[mem] - coprocessor cop0 load/store
+Not supported by the CPU. Trying to execute these opcodes causes a Coprocessor
+Unusable Exception (excode=0Bh, ie. unlike above, not 0Ah).
+
+cop0r16-r31 - Garbage
+Trying to read these registers returns garbage (but does not trigger an
+exception). When reading one of the garbage registers shortly after reading a
+valid cop0 register, the garbage value is usually the same as that of the valid
+register. When doing the read later on, the return value is usually 00000020h,
+or when reading much later it returns 00000040h, or even 00000100h. No idea
+what is causing that effect...?
+Note: The garbage registers can be accessed (without causing an exception) even
+in "User mode with cop0 disabled" (SR.Bit1=1 and SR.Bit28=0); accessing any
+other existing cop0 registers (or executing the rfe opcode) in that state is
+causing Coprocessor Unusable Exceptions (excode=0Bh).
+
+COP0 - Debug Registers
+----------------------
+
+The COP0 debug registers seem to be PSX specific, normal R30xx CPUs like IDT's
+R3041 and R3051 don't have anything similar.
+
+cop0r7 - DCIC - Breakpoint control (R/W)
+ 0 Automatically set by hardware upon Any break (R/W)
+ 1 Automatically set by hardware upon BPC Code break (R/W)
+ 2 Automatically set by hardware upon BDA Data break (R/W)
+ 3 Automatically set by hardware upon BDA Data-Read break (R/W)
+ 4 Automatically set by hardware upon BDA Data-Write break (R/W)
+ 5 Automatically set by hardware upon any-jump break (R/W)
+ 6-11 Not used (always zero)
+ 12-13 Jump Redirection (0=Disable, 1..3=Enable) (see note) (R/W)
+ 14-15 Unknown? (R/W)
+ 16-22 Not used (always zero)
+ 23 Super-Master Enable 1 for bit24-29
+ 24 Execution breakpoint (0=Disabled, 1=Enabled) (see BPC, BPCM)
+ 25 Data access breakpoint (0=Disabled, 1=Enabled) (see BDA, BDAM)
+ 26 Break on Data-Read (0=No, 1=Break/when Bit25=1)
+ 27 Break on Data-Write (0=No, 1=Break/when Bit25=1)
+ 28 Break on any-jump (0=No, 1=Break on branch/jump/call/etc.)
+ 29 Master Enable for bit28 (..and/or exec-break at address>=80000000h?)
+ 30 Master Enable for bit24-27
+ 31 Super-Master Enable 2 for bit24-29
+When a breakpoint address match occurs the PSX jumps to 80000040h (ie. unlike
+normal exceptions, not to 80000080h). The Excode value in the CAUSE register is
+set to 09h (same as BREAK opcode), and EPC contains the return address, as
+usually. One of the first things to be done in the exception handler is to
+disable breakpoints (eg. if the any-jump break is enabled, then it must be
+disabled BEFORE jumping from 80000040h to the actual exception handler).
+
+cop0r7.bit12-13 - Jump Redirection Note
+If one or both of these bits are nonzero, then the PSX seems to check for the
+following opcode sequence,
+ mov rx,[mem] ;load rx from memory
+ ... ;one or more opcodes that do not change rx
+ jmp/call rx ;jump or call to rx
+if it does sense that sequence, then it sets PC=[00000000h], but does not store
+any useful information in any cop0 registers, namely it does not store the
+return address in EPC, so it's impossible to determine which opcode has caused
+the exception. For the jump target address, there are 31 registers, so one
+could only guess which of them contains the target value; for "POP PC" code
+it'd be usually R31, but for "JMP [vector]" code it may be any register. So far
+the feature seems to be more or less unusable...?
+
+cop0r5 - BDA - Breakpoint on Data Access Address (R/W)
+cop0r9 - BDAM - Breakpoint on Data Access Mask (R/W)
+Break condition is "((addr XOR BDA) AND BDAM)=0".
+
+cop0r3 - BPC - Breakpoint on Execute Address (R/W)
+cop0r11 - BPCM - Breakpoint on Execute Mask (R/W)
+Break condition is "((PC XOR BPC) AND BPCM)=0".
+
+Note (BREAK Opcode)
+Additionally, the BREAK opcode can be used to create further breakpoints by
+patching the executable code. The BREAK opcode uses the same Excode value (09h)
+in CAUSE register. However, the BREAK opcode jumps to the normal exception
+handler at 80000080h (not 80000040h).
+
+Note (LibCrypt)
+The debug registers are mis-used by "Legacy of Kain: Soul Reaver" (and maybe
+also other games) for storing libcrypt copy-protection related values (ie. just
+as a "hidden" location for storing data, not for actual debugging purposes).
+--> CDROM Protection - LibCrypt
+
+Note (Cheat Devices/Expansion ROMs)
+The Expansion ROM header supports only Pre-Boot and Post-Boot vectors, but no
+Mid-Boot vector. Cheat Devices are often using COP0 breaks for Mid-Boot Hooks,
+either with BPC=BFC06xxxh (break address in ROM, used in older cheat
+firmwares), or with BPC=80030000h (break address in RAM aka relocated GUI
+entrypoint, used in later cheat firmwares). Moreover, aside from the Mid-Boot
+Hook, the Xplorer cheat device is also supporting a special cheat code that
+uses the COP0 break feature.
+
+Note (Datasheet)
+Note: COP0 debug registers are described in LSI's "L64360" datasheet, chapter
+14. And in their LR33300/LR33310 datasheet, chapter 4.
+
+Kernel (BIOS)
+-------------
+
+--> BIOS Overview
+--> BIOS Memory Map
+--> BIOS Function Summary
+--> BIOS File Functions
+--> BIOS File Execute and Flush Cache
+--> BIOS CDROM Functions
+--> BIOS Memory Card Functions
+--> BIOS Interrupt/Exception Handling
+--> BIOS Event Functions
+--> BIOS Event Summary
+--> BIOS Thread Functions
+--> BIOS Timer Functions
+--> BIOS Joypad Functions
+--> BIOS GPU Functions
+--> BIOS Memory Allocation
+--> BIOS Memory Fill/Copy/Compare (SLOW)
+--> BIOS String Functions
+--> BIOS Number/String/Character Conversion
+--> BIOS Misc Functions
+--> BIOS Internal Boot Functions
+--> BIOS More Internal Functions
+--> BIOS PC File Server
+--> BIOS TTY Console (std_io)
+--> BIOS Character Sets
+--> BIOS Control Blocks
+--> BIOS Boot State
+--> BIOS Versions
+--> BIOS Patches
+
+BIOS Overview
+-------------
+
+BIOS CDROM Boot
+The main purpose of the BIOS is to boot games from CDROM, unfortunately, before
+doing that, it displays the Sony intro. It's also doing some copy protection
+and region checks, and refuses to boot unlicensed games, or illegal copies, or
+games for other regions.
+
+BIOS Bootmenu
+The bootmenu shows up when starting the Playstation without CDROM inserted. The
+menu allows to play Audio CDs, and to erase or copy game positions on Memory
+Cards.
+
+BIOS Functions
+The BIOS contains a number of more or less useful, and probably more or less
+inefficient functions that can be used by software.
+No idea if it's easy to take full control of the CPU, ie. to do all hardware
+access and interrupt handling by software, without using the BIOS at all?
+Eventually the BIOS functions for accessing the CDROM drive are important, not
+sure how complicated/compatible it'd be to access the CDROM drive directly via
+I/O ports... among others, there might be different drives used in different
+versions of the Playstation, which aren't fully compatible with each other?
+
+BIOS Memory
+The BIOS occupies 512Kbyte ROM with 8bit address bus (so the BIOS ROM is rather
+slow, for faster execution, portions of it are relocated to the first 64K of
+RAM). For some very strange reason, the original PSX BIOS executes all ROM
+functions in uncached ROM, which is incredible slow (nocash BIOS uses cached
+ROM, which does work without problems).
+The first 64Kbyte of the 2Mbyte Main RAM are reserved for the BIOS (containing
+exception handlers, jump tables, other data, and relocated code). That reserved
+region does unfortunately include the "valuable" first 32Kbytes (valuable
+because that memory could be accessed directly via [R0+immediate], without
+needing to use R1..R31 as base register).
+
+BIOS Memory Map
+---------------
+
+BIOS ROM Map (512Kbytes)
+ BFC00000h Kernel Part 1 (code/data executed in uncached ROM)
+ BFC10000h Kernel Part 2 (code/data relocated to cached RAM)
+ BFC18000h Intro/Bootmenu (code/data decompressed and relocated to RAM)
+ BFC64000h Character Sets
+
+BIOS ROM Header/Footer
+ BFC00100h Kernel BCD date (YYYYMMDDh)
+ BFC00104h Console Type (see Port 1F802030h, Secondary IRQ10 Controller)
+ BFC00108h Kernel Maker/Version Strings (separated by one or more 00h bytes)
+ BFC7FF32h GUI Version/Copyright Strings (if any) (separated by one 00h byte)
+
+BIOS RAM Map (1st 64Kbytes of RAM) (fixed addresses mainly in 1st 500h bytes)
+ 00000000h 10h Garbage Area (see notes below)
+ 00000010h 30h Unused/reserved
+ 00000040h 20h COP0 debug-break vector (not used by Kernel) (in KSEG0)
+ 00000060h 4 RAM Size (in megabytes) (2 or 8)
+ 00000064h 4 Unknown (set to 00000000h)
+ 00000068h 4 Unknown (set to 000000FFh)
+ 0000006Ch 14h Unused/reserved
+ 00000080h 10h Exception vector (actually in KSEG0, ie. at 80000080h)
+ 00000090h 10h Unused/reserved
+ 000000A0h 10h A(nnh) Function Vector
+ 000000B0h 10h B(nnh) Function Vector
+ 000000C0h 10h C(nnh) Function Vector
+ 000000D0h 30h Unused/reserved
+ 00000100h 58h Table of Tables (BIOS Control Blocks) (see below)
+ 00000158h 28h Unused/reserved
+ 00000180h 80h Command line argument from SYSTEM.CNF; BOOT = fname argument
+ 00000200h 300h A(nnh) Jump Table
+ 00000500h ... Kernel Code/Data (relocated from ROM)
+ 0000Cxxxh ... Unused/reserved
+ 0000DF80h 80h Used for BIOS Patches (ie. used by games, not used by BIOS)
+ 0000DFFCh 4 Response value from Intro/Bootmenu
+ 0000E000h 2000h Kernel Memory; ExCBs, EvCBs, and TCBs allocated via B(00h)
+
+User Memory (not used by Kernel)
+ 00010000h ... Begin of User RAM (Exefile, Data, Heap, Stack, etc.)
+ 001FFF00h ... Default Stacktop (usually in KSEG0)
+ 1F800000h 400h Scratchpad (Data-Cache mis-used as Fast RAM)
+
+Table of Tables (see BIOS Control Blocks for details)
+Each table entry consists of two 32bit values; containing the base address, and
+total size (in bytes) of the corresponding control blocks.
+ 00000100h ExCB Exception Chain Entrypoints (addr=var, size=4*08h)
+ 00000108h PCB Process Control Block (addr=var, size=1*04h)
+ 00000110h TCB Thread Control Blocks (addr=var, size=N*C0h)
+ 00000118h - Unused/reserved
+ 00000120h EvCB Event Control Blocks (addr=var, size=N*1Ch)
+ 00000128h - Unused/reserved
+ 00000130h - Unused/reserved
+ 00000138h - Unused/reserved
+ 00000140h FCB File Control Blocks (addr=fixed, size=10h*2Ch)
+ 00000148h - Unused/reserved
+ 00000150h DCB Device Control Blocks (addr=fixed, size=0Ah*50h)
+File handles (fd=00h..0Fh) can be simply converted as fcb=[140h]+fd*2Ch.
+Event handles (event=F10000xxh) as evcb=[120h]+(event AND FFFFh)*1Ch.
+
+Garbage Area at Address 00000000h
+The first some bytes of memory address 00000000h aren't actually used by the
+Kernel, except for storing some garbage at that locations. However, this
+garbage is actually important for bugged games like R-Types and Fade to Black
+(ie. games that do read from address 00000000h due to using uninitialized
+pointers).
+Initially, the garbage area is containing a copy of the 16-byte exception
+handler at address 80h, but the first 4-bytes are typically smashed (set to
+00000003h from some useless dummy writes in some useless CDROM delays). Ie. the
+16-bytes should have these values:
+ [00000000h]=3C1A0000h ;<-- but overwritten by 00000003h after soon
+ [00000004h]=275A0C80h ;<-- or 275A0C50h (in older BIOS)
+ [00000008h]=03400008h
+ [0000000Ch]=00000000h
+For R-Types, the halfword at [0] must non-zero (else the game will do a DMA to
+address 0, and thereby destroy kernel memory). Fade to Black does several
+garbage reads from [0..9], a wrong byte value at [5] can cause the game to
+crash with an invalid memory access exception upon memory card access.
+
+BIOS Function Summary
+---------------------
+
+Parameters, Registers, Stack
+Argument(s) are passed in R4,R5,R6,R7,[SP+10h],[SP+14h],etc.
+Caution: When calling a sub-function with N parameters, the caller MUST always
+allocate N words on the stack, and, although the first four parameters are
+passed in registers rather than on stack, the sub-function is allowed to
+use/destroy these words at [SP+0..N*4-1].
+BIOS Functions (and custom callback functions) are allowed to destroy registers
+R1-R15, R24-R25, R31 (RA), and HI/LO. Registers R16-R23, R29 (SP), and R30 (FP)
+must be left unchanged (if the function uses that registers, then it must
+push/pop them). R26 (K0) is reserved for exception handler and should be
+usually not used by other functions. R27 (K1) and R28 (GP) are left more or
+less unused by the BIOS, so one can more or less freely use them for whatever
+purpose.
+The return value (if any) is stored in R2 register.
+
+A-Functions (Call 00A0h with function number in R9 Register)
+ A(00h) or B(32h) FileOpen(filename,accessmode)
+ A(01h) or B(33h) FileSeek(fd,offset,seektype)
+ A(02h) or B(34h) FileRead(fd,dst,length)
+ A(03h) or B(35h) FileWrite(fd,src,length)
+ A(04h) or B(36h) FileClose(fd)
+ A(05h) or B(37h) FileIoctl(fd,cmd,arg)
+ A(06h) or B(38h) exit(exitcode)
+ A(07h) or B(39h) FileGetDeviceFlag(fd)
+ A(08h) or B(3Ah) FileGetc(fd)
+ A(09h) or B(3Bh) FilePutc(char,fd)
+ A(0Ah) todigit(char)
+ A(0Bh) atof(src) ;Does NOT work - uses (ABSENT) cop1 !!!
+ A(0Ch) strtoul(src,src_end,base)
+ A(0Dh) strtol(src,src_end,base)
+ A(0Eh) abs(val)
+ A(0Fh) labs(val)
+ A(10h) atoi(src)
+ A(11h) atol(src)
+ A(12h) atob(src,num_dst)
+ A(13h) SaveState(buf)
+ A(14h) RestoreState(buf,param)
+ A(15h) strcat(dst,src)
+ A(16h) strncat(dst,src,maxlen)
+ A(17h) strcmp(str1,str2)
+ A(18h) strncmp(str1,str2,maxlen)
+ A(19h) strcpy(dst,src)
+ A(1Ah) strncpy(dst,src,maxlen)
+ A(1Bh) strlen(src)
+ A(1Ch) index(src,char)
+ A(1Dh) rindex(src,char)
+ A(1Eh) strchr(src,char) ;exactly the same as "index"
+ A(1Fh) strrchr(src,char) ;exactly the same as "rindex"
+ A(20h) strpbrk(src,list)
+ A(21h) strspn(src,list)
+ A(22h) strcspn(src,list)
+ A(23h) strtok(src,list) ;use strtok(0,list) in further calls
+ A(24h) strstr(str,substr) - buggy
+ A(25h) toupper(char)
+ A(26h) tolower(char)
+ A(27h) bcopy(src,dst,len)
+ A(28h) bzero(dst,len)
+ A(29h) bcmp(ptr1,ptr2,len) ;Bugged
+ A(2Ah) memcpy(dst,src,len)
+ A(2Bh) memset(dst,fillbyte,len)
+ A(2Ch) memmove(dst,src,len) ;Bugged
+ A(2Dh) memcmp(src1,src2,len) ;Bugged
+ A(2Eh) memchr(src,scanbyte,len)
+ A(2Fh) rand()
+ A(30h) srand(seed)
+ A(31h) qsort(base,nel,width,callback)
+ A(32h) strtod(src,src_end) ;Does NOT work - uses (ABSENT) cop1 !!!
+ A(33h) malloc(size)
+ A(34h) free(buf)
+ A(35h) lsearch(key,base,nel,width,callback)
+ A(36h) bsearch(key,base,nel,width,callback)
+ A(37h) calloc(sizx,sizy) ;SLOW!
+ A(38h) realloc(old_buf,new_siz) ;SLOW!
+ A(39h) InitHeap(addr,size)
+ A(3Ah) SystemErrorExit(exitcode)
+ A(3Bh) or B(3Ch) std_in_getchar()
+ A(3Ch) or B(3Dh) std_out_putchar(char)
+ A(3Dh) or B(3Eh) std_in_gets(dst)
+ A(3Eh) or B(3Fh) std_out_puts(src)
+ A(3Fh) printf(txt,param1,param2,etc.)
+ A(40h) SystemErrorUnresolvedException()
+ A(41h) LoadExeHeader(filename,headerbuf)
+ A(42h) LoadExeFile(filename,headerbuf)
+ A(43h) DoExecute(headerbuf,param1,param2)
+ A(44h) FlushCache()
+ A(45h) init_a0_b0_c0_vectors
+ A(46h) GPU_dw(Xdst,Ydst,Xsiz,Ysiz,src)
+ A(47h) gpu_send_dma(Xdst,Ydst,Xsiz,Ysiz,src)
+ A(48h) SendGP1Command(gp1cmd)
+ A(49h) GPU_cw(gp0cmd) ;send GP0 command word
+ A(4Ah) GPU_cwp(src,num) ;send GP0 command word and parameter words
+ A(4Bh) send_gpu_linked_list(src)
+ A(4Ch) gpu_abort_dma()
+ A(4Dh) GetGPUStatus()
+ A(4Eh) gpu_sync()
+ A(4Fh) SystemError
+ A(50h) SystemError
+ A(51h) LoadAndExecute(filename,stackbase,stackoffset)
+ A(52h) SystemError ----OR---- "GetSysSp()" ?
+ A(53h) SystemError ;PS2: set_ioabort_handler(src)
+ A(54h) or A(71h) CdInit()
+ A(55h) or A(70h) _bu_init()
+ A(56h) or A(72h) CdRemove()
+ A(57h) return 0
+ A(58h) return 0
+ A(59h) return 0
+ A(5Ah) return 0
+ A(5Bh) dev_tty_init() ;PS2: SystemError
+ A(5Ch) dev_tty_open(fcb,and unused:"path\name",accessmode) ;PS2: SystemError
+ A(5Dh) dev_tty_in_out(fcb,cmd) ;PS2: SystemError
+ A(5Eh) dev_tty_ioctl(fcb,cmd,arg) ;PS2: SystemError
+ A(5Fh) dev_cd_open(fcb,"path\name",accessmode)
+ A(60h) dev_cd_read(fcb,dst,len)
+ A(61h) dev_cd_close(fcb)
+ A(62h) dev_cd_firstfile(fcb,"path\name",direntry)
+ A(63h) dev_cd_nextfile(fcb,direntry)
+ A(64h) dev_cd_chdir(fcb,"path")
+ A(65h) dev_card_open(fcb,"path\name",accessmode)
+ A(66h) dev_card_read(fcb,dst,len)
+ A(67h) dev_card_write(fcb,src,len)
+ A(68h) dev_card_close(fcb)
+ A(69h) dev_card_firstfile(fcb,"path\name",direntry)
+ A(6Ah) dev_card_nextfile(fcb,direntry)
+ A(6Bh) dev_card_erase(fcb,"path\name")
+ A(6Ch) dev_card_undelete(fcb,"path\name")
+ A(6Dh) dev_card_format(fcb)
+ A(6Eh) dev_card_rename(fcb1,"path\name1",fcb2,"path\name2")
+ A(6Fh) ? ;card ;[r4+18h]=00000000h ;card_clear_error(fcb) or so
+ A(70h) or A(55h) _bu_init()
+ A(71h) or A(54h) CdInit()
+ A(72h) or A(56h) CdRemove()
+ A(73h) return 0
+ A(74h) return 0
+ A(75h) return 0
+ A(76h) return 0
+ A(77h) return 0
+ A(78h) CdAsyncSeekL(src)
+ A(79h) return 0 ;DTL-H: Unknown?
+ A(7Ah) return 0 ;DTL-H: Unknown?
+ A(7Bh) return 0 ;DTL-H: Unknown?
+ A(7Ch) CdAsyncGetStatus(dst)
+ A(7Dh) return 0 ;DTL-H: Unknown?
+ A(7Eh) CdAsyncReadSector(count,dst,mode)
+ A(7Fh) return 0 ;DTL-H: Unknown?
+ A(80h) return 0 ;DTL-H: Unknown?
+ A(81h) CdAsyncSetMode(mode)
+ A(82h) return 0 ;DTL-H: Unknown?
+ A(83h) return 0 ;DTL-H: Unknown?
+ A(84h) return 0 ;DTL-H: Unknown?
+ A(85h) return 0 ;DTL-H: Unknown?, or reportedly, CdStop (?)
+ A(86h) return 0 ;DTL-H: Unknown?
+ A(87h) return 0 ;DTL-H: Unknown?
+ A(88h) return 0 ;DTL-H: Unknown?
+ A(89h) return 0 ;DTL-H: Unknown?
+ A(8Ah) return 0 ;DTL-H: Unknown?
+ A(8Bh) return 0 ;DTL-H: Unknown?
+ A(8Ch) return 0 ;DTL-H: Unknown?
+ A(8Dh) return 0 ;DTL-H: Unknown?
+ A(8Eh) return 0 ;DTL-H: Unknown?
+ A(8Fh) return 0 ;DTL-H: Unknown?
+ A(90h) CdromIoIrqFunc1()
+ A(91h) CdromDmaIrqFunc1()
+ A(92h) CdromIoIrqFunc2()
+ A(93h) CdromDmaIrqFunc2()
+ A(94h) CdromGetInt5errCode(dst1,dst2)
+ A(95h) CdInitSubFunc()
+ A(96h) AddCDROMDevice()
+ A(97h) AddMemCardDevice() ;DTL-H: SystemError
+ A(98h) AddDuartTtyDevice() ;DTL-H: AddAdconsTtyDevice ;PS2: SystemError
+ A(99h) AddDummyTtyDevice()
+ A(9Ah) SystemError ;DTL-H: AddMessageWindowDevice
+ A(9Bh) SystemError ;DTL-H: AddCdromSimDevice
+ A(9Ch) SetConf(num_EvCB,num_TCB,stacktop)
+ A(9Dh) GetConf(num_EvCB_dst,num_TCB_dst,stacktop_dst)
+ A(9Eh) SetCdromIrqAutoAbort(type,flag)
+ A(9Fh) SetMemSize(megabytes)
+Below functions A(A0h..B4h) not supported on pre-retail DTL-H2000 devboard:
+ A(A0h) WarmBoot()
+ A(A1h) SystemErrorBootOrDiskFailure(type,errorcode)
+ A(A2h) EnqueueCdIntr() ;with prio=0 (fixed)
+ A(A3h) DequeueCdIntr()
+ A(A4h) CdGetLbn(filename) ;get 1st sector number (or garbage when not found)
+ A(A5h) CdReadSector(count,sector,buffer)
+ A(A6h) CdGetStatus()
+ A(A7h) bu_callback_okay()
+ A(A8h) bu_callback_err_write()
+ A(A9h) bu_callback_err_busy()
+ A(AAh) bu_callback_err_eject()
+ A(ABh) _card_info(port)
+ A(ACh) _card_async_load_directory(port)
+ A(ADh) set_card_auto_format(flag)
+ A(AEh) bu_callback_err_prev_write()
+ A(AFh) card_write_test(port) ;CEX-1000: jump_to_00000000h
+ A(B0h) return 0 ;CEX-1000: jump_to_00000000h
+ A(B1h) return 0 ;CEX-1000: jump_to_00000000h
+ A(B2h) ioabort_raw(param) ;CEX-1000: jump_to_00000000h
+ A(B3h) return 0 ;CEX-1000: jump_to_00000000h
+ A(B4h) GetSystemInfo(index) ;CEX-1000: jump_to_00000000h
+ A(B5h..BFh) N/A ;jump_to_00000000h
+
+B-Functions (Call 00B0h with function number in R9 Register)
+ B(00h) alloc_kernel_memory(size)
+ B(01h) free_kernel_memory(buf)
+ B(02h) init_timer(t,reload,flags)
+ B(03h) get_timer(t)
+ B(04h) enable_timer_irq(t)
+ B(05h) disable_timer_irq(t)
+ B(06h) restart_timer(t)
+ B(07h) DeliverEvent(class, spec)
+ B(08h) OpenEvent(class,spec,mode,func)
+ B(09h) CloseEvent(event)
+ B(0Ah) WaitEvent(event)
+ B(0Bh) TestEvent(event)
+ B(0Ch) EnableEvent(event)
+ B(0Dh) DisableEvent(event)
+ B(0Eh) OpenThread(reg_PC,reg_SP_FP,reg_GP)
+ B(0Fh) CloseThread(handle)
+ B(10h) ChangeThread(handle)
+ B(11h) jump_to_00000000h
+ B(12h) InitPad(buf1,siz1,buf2,siz2)
+ B(13h) StartPad()
+ B(14h) StopPad()
+ B(15h) OutdatedPadInitAndStart(type,button_dest,unused,unused)
+ B(16h) OutdatedPadGetButtons()
+ B(17h) ReturnFromException()
+ B(18h) SetDefaultExitFromException()
+ B(19h) SetCustomExitFromException(addr)
+ B(1Ah) SystemError ;PS2: return 0
+ B(1Bh) SystemError ;PS2: return 0
+ B(1Ch) SystemError ;PS2: return 0
+ B(1Dh) SystemError ;PS2: return 0
+ B(1Eh) SystemError ;PS2: return 0
+ B(1Fh) SystemError ;PS2: return 0
+ B(20h) UnDeliverEvent(class,spec)
+ B(21h) SystemError ;PS2: return 0
+ B(22h) SystemError ;PS2: return 0
+ B(23h) SystemError ;PS2: return 0
+ B(24h) jump_to_00000000h
+ B(25h) jump_to_00000000h
+ B(26h) jump_to_00000000h
+ B(27h) jump_to_00000000h
+ B(28h) jump_to_00000000h
+ B(29h) jump_to_00000000h
+ B(2Ah) SystemError ;PS2: return 0
+ B(2Bh) SystemError ;PS2: return 0
+ B(2Ch) jump_to_00000000h
+ B(2Dh) jump_to_00000000h
+ B(2Eh) jump_to_00000000h
+ B(2Fh) jump_to_00000000h
+ B(30h) jump_to_00000000h
+ B(31h) jump_to_00000000h
+ B(32h) or A(00h) FileOpen(filename,accessmode)
+ B(33h) or A(01h) FileSeek(fd,offset,seektype)
+ B(34h) or A(02h) FileRead(fd,dst,length)
+ B(35h) or A(03h) FileWrite(fd,src,length)
+ B(36h) or A(04h) FileClose(fd)
+ B(37h) or A(05h) FileIoctl(fd,cmd,arg)
+ B(38h) or A(06h) exit(exitcode)
+ B(39h) or A(07h) FileGetDeviceFlag(fd)
+ B(3Ah) or A(08h) FileGetc(fd)
+ B(3Bh) or A(09h) FilePutc(char,fd)
+ B(3Ch) or A(3Bh) std_in_getchar()
+ B(3Dh) or A(3Ch) std_out_putchar(char)
+ B(3Eh) or A(3Dh) std_in_gets(dst)
+ B(3Fh) or A(3Eh) std_out_puts(src)
+ B(40h) chdir(name)
+ B(41h) FormatDevice(devicename)
+ B(42h) firstfile(filename,direntry)
+ B(43h) nextfile(direntry)
+ B(44h) FileRename(old_filename,new_filename)
+ B(45h) FileDelete(filename)
+ B(46h) FileUndelete(filename)
+ B(47h) AddDevice(device_info) ;subfunction for AddXxxDevice functions
+ B(48h) RemoveDevice(device_name_lowercase)
+ B(49h) PrintInstalledDevices()
+Below functions B(4Ah..5Dh) not supported on pre-retail DTL-H2000 devboard:
+ B(4Ah) InitCard(pad_enable) ;uses/destroys k0/k1 !!!
+ B(4Bh) StartCard()
+ B(4Ch) StopCard()
+ B(4Dh) _card_info_subfunc(port) ;subfunction for "_card_info"
+ B(4Eh) write_card_sector(port,sector,src)
+ B(4Fh) read_card_sector(port,sector,dst)
+ B(50h) allow_new_card()
+ B(51h) Krom2RawAdd(shiftjis_code)
+ B(52h) SystemError ;PS2: return 0
+ B(53h) Krom2Offset(shiftjis_code)
+ B(54h) GetLastError()
+ B(55h) GetLastFileError(fd)
+ B(56h) GetC0Table
+ B(57h) GetB0Table
+ B(58h) get_bu_callback_port()
+ B(59h) testdevice(devicename)
+ B(5Ah) SystemError ;PS2: return 0
+ B(5Bh) ChangeClearPad(int)
+ B(5Ch) get_card_status(slot)
+ B(5Dh) wait_card_status(slot)
+ B(5Eh..FFh) N/A ;jump_to_00000000h ;CEX-1000: B(5Eh..F6h) only
+ B(100h....) N/A ;garbage ;CEX-1000: B(F7h.....) and up
+
+C-Functions (Call 00C0h with function number in R9 Register)
+ C(00h) EnqueueTimerAndVblankIrqs(priority) ;used with prio=1
+ C(01h) EnqueueSyscallHandler(priority) ;used with prio=0
+ C(02h) SysEnqIntRP(priority,struc)
+ C(03h) SysDeqIntRP(priority,struc)
+ C(04h) get_free_EvCB_slot()
+ C(05h) get_free_TCB_slot()
+ C(06h) ExceptionHandler()
+ C(07h) InstallExceptionHandlers() ;destroys/uses k0/k1
+ C(08h) SysInitMemory(addr,size)
+ C(09h) SysInitKernelVariables()
+ C(0Ah) ChangeClearRCnt(t,flag)
+ C(0Bh) SystemError ;PS2: return 0
+ C(0Ch) InitDefInt(priority) ;used with prio=3
+ C(0Dh) SetIrqAutoAck(irq,flag)
+ C(0Eh) return 0 ;DTL-H2000: dev_sio_init
+ C(0Fh) return 0 ;DTL-H2000: dev_sio_open
+ C(10h) return 0 ;DTL-H2000: dev_sio_in_out
+ C(11h) return 0 ;DTL-H2000: dev_sio_ioctl
+ C(12h) InstallDevices(ttyflag)
+ C(13h) FlushStdInOutPut()
+ C(14h) return 0 ;DTL-H2000: SystemError
+ C(15h) tty_cdevinput(circ,char)
+ C(16h) tty_cdevscan()
+ C(17h) tty_circgetc(circ) ;uses r5 as garbage txt for ioabort
+ C(18h) tty_circputc(char,circ)
+ C(19h) ioabort(txt1,txt2)
+ C(1Ah) set_card_find_mode(mode) ;0=normal, 1=find deleted files
+ C(1Bh) KernelRedirect(ttyflag) ;PS2: ttyflag=1 causes SystemError
+ C(1Ch) AdjustA0Table()
+ C(1Dh) get_card_find_mode()
+ C(1Eh..7Fh) N/A ;jump_to_00000000h
+ C(80h.....) N/A ;mirrors to B(00h.....)
+
+SYS-Functions (Syscall opcode with function number in R4 aka A0 Register)
+ SYS(00h) NoFunction()
+ SYS(01h) EnterCriticalSection()
+ SYS(02h) ExitCriticalSection()
+ SYS(03h) ChangeThreadSubFunction(addr) ;syscall with r4=03h, r5=addr
+ SYS(04h..FFFFFFFFh) calls DeliverEvent(F0000010h,4000h)
+The 20bit immediate in the "syscall imm" opcode is unused (should be zero).
+
+BREAK-Functions (Break opcode with function number in opcode's immediate)
+BRK opcodes may be used within devkits, however, the standard BIOS simply calls
+DeliverEvent(F0000010h,1000h) and SystemError_A_40h upon any BRK opcodes (as
+well as on any other unresolved exceptions).
+ BRK(1C00h) Division by zero (commonly checked/invoked by software)
+ BRK(1800h) Division overflow (-80000000h/-1, sometimes checked by software)
+Below breaks are used in DTL-H2000 BIOS:
+ BRK(1h) Whatever lockup or so?
+ BRK(101h) PCInit() Inits the fileserver
+ BRK(102h) PCCreat(filename, fileattributes)
+ BRK(103h) PCOpen(filename, accessmode)
+ BRK(104h) PCClose(filehandle)
+ BRK(105h) PCRead(filehandle, length, memory_destination_address)
+ BRK(106h) PCWrite(filehandle, length, memory_source_address)
+ BRK(107h) PClSeek(filehandle, file_offset, seekmode)
+ BRK(3C400h) User has typed "break" command in debug console
+The break functions have argument(s) in A1,A2,A3 (ie. unlike normal BIOS
+functions not in A0,A1,A2), and TWO return values (in R2, and R3). These
+functions require a commercial/homebrew devkit... consisting of a Data Cable
+(for accessing the PC's harddisk)... and an Expansion ROM (for handling the
+BREAK opcodes)... or so?
+
+BIOS File Functions
+-------------------
+
+A(00h) or B(32h) - FileOpen(filename, accessmode) - Opens a file for IO
+ out: V0 File handle (00h..0Fh), or -1 if error.
+Opens a file on the target device for io. Accessmode is set like this:
+ bit0 1=Read ;\These bits aren't actually used by the BIOS, however, at
+ bit1 1=Write ;/least 1 should be set; won't work when all 32bits are zero
+ bit2 1=Exit without waiting for incoming data (when TTY buffer empty)
+ bit9 0=Open Existing File, 1=Create New file (memory card only)
+ bit15 1=Asynchronous mode (memory card only; don't wait for completion)
+ bit16-31 Number of memory card blocks for a new file on the memory card
+The PSX can have a maximum of 16 files open at any time, of which, 2 handles
+are always reserved for std_io, so only 14 handles are available for actual
+files. Some functions (chdir, testdevice, FileDelete, FileUndelete,
+FormatDevice, firstfile, FileRename) are temporarily allocating 1 filehandle
+(FileRename tries to use 2 filehandles, but, it does accidently use only 1
+handle, too). So, for example, FileDelete would fail if more than 13 file
+handles are opened by the game.
+
+A(01h) or B(33h) - FileSeek(fd, offset, seektype) - Move the file pointer
+ seektype 0 = from start of file (with positive offset)
+ 1 = from current file pointer (with positive/negative offset)
+ 2 = Bugs. Should be from end of file.
+Moves the file pointer the number of bytes in A1, relative to the location
+specified by A2. Movement from the eof is incorrect. Also, movement beyond the
+end of the file is not checked.
+
+A(02h) or B(34h) - FileRead(fd, dst, length) - Read data from an open file
+ out: V0 Number of bytes actually read, -1 if failed.
+Reads the number of bytes from the specified open file. If length is not
+specified an error is returned. Read per $0080 bytes from memory card (bu:) and
+per $0800 from cdrom (cdrom:).
+
+A(03h) or B(35h) - FileWrite(fd, src, length) - Write data to an open file
+ out: V0 Number of bytes written.
+Writes the number of bytes to the specified open file. Write to the memory card
+per $0080 bytes. Writing to the cdrom returns 0.
+
+A(04h) or B(36h) - FileClose(fd) - Close an open file
+Returns r2=fd (or r2=-1 if failed).
+
+A(08h) or B(3Ah) - FileGetc(fd) - read one byte from file
+ out: R2=character (sign-expanded) or FFFFFFFFh=error
+Internally redirects to "FileRead(fd,tempbuf,1)". For some strange reason, the
+returned character is sign-expanded; so, a return value of FFFFFFFFh could mean
+either character FFh, or error.
+
+A(09h) or B(3Bh) - FilePutc(char,fd) - write one byte to file
+Observe that "fd" is the 2nd paramter (not the 1st paramter as usually).
+ out: R2=Number of bytes actually written, -1 if failed
+Internally redirects to "FileWrite(fd,tempbuf,1)".
+
+B(40h) - chdir(name) - Change the current directory on target device
+Changes the current directory on the specified device, which should be "cdrom:"
+(memory cards don't support directories). The PSX supports only a current
+directory, but NOT a current device (ie. after chdir, the directory name may be
+ommited from filenames, but the device name must be still included in all
+filenames).
+ in: A0 Pointer to new directory path (eg. "cdrom:\path")
+Returns 1=okay, or 0=failed.
+The function doesn't verify if the directory exists. Caution: For cdrom, the
+function does always load the path table from the disk (even if it was already
+stored in RAM, so chdir is causing useless SLOW read/seek delays).
+
+B(42h) - firstfile(filename,direntry) - Find first file to match the name
+Returns r2=direntry (or r2=0 if no matching files).
+Searches for the first file to match the specified filename; the filename may
+contain "?" and "*" wildcards. "*" means to ignore ALL following characters;
+accordingly one cannot specify any further characters after the "*" (eg.
+"DATA*" would work, but "*.DAT" won't work). "?" is meant to ignore a single
+character cell. Note: The "?" wildcards (but not "*") can be used also in all
+other file functions; causing the function to use the first matching name (eg.
+FileDelete "????" would erase the first matching file, not all matching files).
+Start the name with the device you want to address. (ie. pcdrv:) Different
+drives can be accessed as normally by their drive names (a:, c:, huh?) if path
+is omitted after the device, the current directory will be used.
+A direntry structure looks like this:
+ 00h 14h Filename, terminated with 00h
+ 14h 4 File attribute (always 0 for cdrom) (50h=norm or A0h=del for card)
+ 18h 4 File size
+ 1Ch 4 Pointer to next direntry? (not used?)
+ 20h 4 First Sector Number
+ 24h 4 Reserved (not used)
+BUG: If "?" matches the ending 00h byte of a name, then any further characters
+in the search expression are ignored (eg. "FILE?.DAT" would match to
+"FILE2.DAT", but accidently also to "FILE").
+BUG: For CDROM, the BIOS includes some code that is intended to realize disk
+changes during firstfile/nextfile operations, however, that code is so bugged
+that it does rather ensure that the BIOS does NOT realize new disks being
+inserted during firstfile/nextfile.
+BUG: firstfile/nextfile is internally using a FCB. On the first call to
+firstfile, the BIOS is searching a free FCB, and does apply that as "search
+fcb", but it doesn't mark that FCB as allocated, so other file functions may
+accidently use the same FCB. Moreover, the BIOS does memorize that "search
+fcb", and, even when starting a new search via another call to firstfile, it
+keeps using that FCB for search (without checking if the FCB is still free). A
+possible workaround is not to have any files opened during firstfile/nextfile
+operations.
+
+B(43h) - nextfile(direntry) - Searches for the next file to match the name
+Returns r2=direntry (or r2=0 if no more matching files).
+Uses the settings of a previous firstfile/nextfile command.
+
+B(44h) - FileRename(old_filename, new_filename)
+Returns 1=okay, or 0=failed.
+
+B(45h) - FileDelete(filename) - Delete a file on target device
+Returns 1=okay, or 0=failed.
+
+B(46h) - FileUndelete(filename)
+Returns 1=okay, or 0=failed.
+
+B(41h) - FormatDevice(devicename)
+Erases all files on the device (ie. for formatting memory cards).
+Returns 1=okay, or 0=failed.
+
+B(54h) - GetLastError()
+Indicates the reason of the most recent file function error (FileOpen,
+FileSeek, FileRead, FileWrite, FileClose, GetLastFileError, FileIoctl, chdir,
+testdevice, FileDelete, FileUndelete, FormatDevice, FileRename). Use
+GetLastError() ONLY if an error has occured (the error code isn't reset to zero
+by functions that are passing okay). firstfile/nextfile do NOT affect
+GetLastError(). See below list of File Error Numbers for more info.
+
+B(55h) - GetLastFileError(fd)
+Basically same as B(54h), but allowing to specify a file handle for which error
+information is to be received; accordingly it doesn't work for functions that
+do use 'hidden' internal file handles (eg. FileDelete, or unsuccessful
+FileOpen). Returns FCB[18h], or FFFFFFFFh if the handle is invalid/unused.
+
+A(05h) or B(37h) FileIoctl(fd,cmd,arg)
+Used only for TTY.
+
+A(07h) or B(39h) FileGetDeviceFlag(fd)
+Returns bit1 of the file's DCB flags. That bit is set only for Duart/TTY, and
+is cleared for Dummy/TTY, Memory Card, and CDROM.
+
+B(59h) - testdevice(devicename)
+Whatever. Checks the devicename, and if it's accepted, calls a device specific
+function. For the existing devices (cdrom,bu,tty) that specific function simply
+returns without doing anything. Maybe other devices (like printers or modems)
+would do something more interesting.
+
+File Error Numbers for B(54h) and B(55h)
+ 00h okay (though many successful functions leave old error code unchanged)
+ 02h file not found
+ 06h bad device port number (tty2 and up)
+ 09h invalid or unused file handle
+ 10h general error (physical I/O error, unformatted, disk changed for old fcb)
+ 11h file already exists error (create/undelete/rename)
+ 12h tried to rename a file from one device to another device
+ 13h unknown device name
+ 16h sector alignment error, or fpos>=filesize, unknown seektype or ioctl cmd
+ 18h not enough free file handles
+ 1Ch not enough free memory card blocks
+ FFFFFFFFh invalid or unused file handle passed to B(55h) function
+
+BIOS File Execute and Flush Cache
+---------------------------------
+
+A(41h) - LoadExeHeader(filename, headerbuf)
+Loads the 800h-byte exe file header to an internal sector buffer, and does then
+copy bytes [10h..4Bh] of that header to headerbuf[00h..3Bh].
+
+A(42h) - LoadExeFile(filename, headerbuf)
+Same as LoadExeHeader (see there for details), but additionally loads the body
+of the executable (using the size and destination address in the file header),
+and does call FlushCache. The exe can be then started via DoExecute (this isn't
+done automatically by LoadExeFile). Unlike "LoadAndExecute", the
+"LoadExeFile/DoExecute" combination allows to return the new exe file to return
+to the old exe file (instead of restarting the boot executable).
+BUG: Uses the unstable FlushCache function (see there for details).
+
+A(43h) - DoExecute(headerbuf, param1, param2)
+Can be used to start a previously loaded executable. The function saves
+R16,R28,R30,SP,RA in the reserved region of headerbuf (rather than on stack),
+more or less slowly zerofills the memfill region specified in headerbuf, reads
+the stack base and offset values and sets SP and FP to base+offset (or leaves
+them unchanged if base=0), reads the GP value from headerbuf and sets GP to
+that value. Then calls the excecutables entrypoint, with param1 and param2
+passed in r4,r5.
+If the executable (should) return, then R16,R28,R30,SP,RA are restored from
+headerbuf, and the function returns with r2=1.
+
+A(51h) - LoadAndExecute(filename, stackbase, stackoffset)
+This is a rather bizarre function. In short, it does load and execute the
+specified file, and thereafter, it (tries to) reload and restart to boot
+executable.
+Part1: Takes a copy of the filename, with some adjustments: Everything up to
+the first ":" or 00h byte is copied as is (ie. the device name, if it does
+exist, or otherwise the whole path\filename.ext;ver), the remaining characters
+are copied and converted to uppercase (ie. the path\filename.ext;ver part, or
+none if the device name didn't exist), finally, checks if a ";" exists (ie. the
+version suffix), if there's none, then it appends ";1" as default version.
+CAUTION: The BIOS allocates ONLY 28 bytes on stack for the copy of the
+filename, that region is followed by 4 unused bytes, so the maximum length
+would be 32 bytes (31 characters plus EOL) (eg.
+"device:\pathname\filename.ext;1",00h).
+Part2: Enables IRQs via ExitCriticalSection, memorizes the stack base/offset
+values from the previously loaded executable (which should have been the boot
+executable, unless LoadAndExecute should have been used in nested fashion),
+does then use LoadExeFile to load the desired file, replaces the stack
+base/offset values in its headerbuf by the LoadAndExecute parameter values, and
+does then execute it via DoExecute(headerbuf,1,0).
+Part3: If the exefile returns, or if it couldn't be loaded, then the boot file
+is (unsuccessfully) attempted to be reloaded: Enables IRQs via
+ExitCriticalSection, loads the boot file via LoadExeFile, replaces the stack
+base/offset values in its headerbuf by the values memorized in Part2 (which
+<should> be the boot executable's values from SYSTEM.CNF, unless the nesting
+stuff occurred), and does then execute the boot file via
+DoExecute(headerbuf,1,0).
+Part4: If the boot file returns, or if it couldn't be loaded, then the function
+looks up in a "JMP $" endless loop (normally, returning from the boot exe
+causes SystemErrorBootOrDiskFailure("B",38Ch), however, after using
+LoadAndExecute, this functionality is replaced by the "JMP $" lockup.
+BUG: Uses the unstable FlushCache function (see there for details).
+BUG: Part3 accidently treats the first 4 characters of the exename as memory
+address (causing an invalid memory address exception on address 6F726463h, for
+"cdrom:filename.exe").
+
+A(9Ch) - SetConf(num_EvCB, num_TCB, stacktop)
+Changes the number of EvCBs and TCBs, and the stacktop. That values are usually
+initialized from the settings in the SYSTEM.CNF file, so using this function
+usually shouldn't ever be required.
+The function deallocates all old ExCBs, EvCBs, TCBs (so all Exception handlers,
+Events, and Threads (except the current one) are lost, and all other memory
+that may have been allocated via alloc_kernel_memory(size) is deallocated, too.
+It does then allocate the new control blocks, and enqueue the default handlers.
+Despite of the changed stacktop, the current stack pointer is kept intact, and
+the function returns to the caller.
+
+A(9Dh) - GetConf(num_EvCB_dst, num_TCB_dst, stacktop_dst)
+Returns the number of EvCBs, TCBs, and the initial stacktop. There's no return
+value in the R2 register, instead, the three 32bit return values are stored at
+the specified "dst" addresses.
+
+A(44h) - FlushCache()
+Flushes the Code Cache, so opcodes are ensured to be loaded from RAM. This is
+required when loading program code via DMA (ie. from CDROM) (the cache
+controller apparently doesn't realize changes to RAM that are caused by DMA).
+The LoadExeFile and LoadAndExecute functions are automatically calling
+FlushCache (so FlushCache is required only when loading program code via
+"FileRead" or via "CdReadSector").
+FlushCache may be also required when relocating or modifying program code by
+software (the cache controller doesn't seem to realize modifications to memory
+mirrors, eg. patching the exception handler at 80000080h seems to be work
+without FlushCache, but patching the same bytes at 00000080h doesn't).
+Note: The PSX doesn't have a Data Cache (or actually, it has, but it's misused
+as Fast RAM, mapped to a fixed memory region, and which isn't accessable by
+DMA), so FlushCache isn't required for regions that contain data.
+BUG: The FlushCache function contains a handful of opcodes that do use the k0
+register without having IRQs disabled at that time, if an IRQ occurs during
+those opcodes, then the k0 value gets destroyed by the exception handler,
+causing FlushCache to get trapped in an endless loop.
+One workaround would be to disable all IRQs before calling FlushCache, however,
+the BIOS does internally call the function without IRQs disabled, that applies
+to:
+ load_file A(42h)
+ load_exec A(51h)
+ add_device B(47h) (and all "add_xxx_device" functions)
+ init_card B(4Ah)
+ and by intro/boot code
+for load_file/load_exec, IRQ2 (cdrom) and IRQ3 (dma) need to be enabled, so the
+"disable all IRQs" workaround cannot be used for that functions, however, one
+can/should disable as many IRQs as possible, ie. everything except IRQ2/IRQ3,
+and all DMA interrupts except DMA3 (cdrom).
+
+Executable Memory Allocation
+LoadExeFile and LoadAndExecute are simply loading the file to the address
+specified in the exe file header. There's absolutely no verification whether
+that memory is (or isn't) allocated via malloc, or if it is used by the boot
+executable, or by the kernel, or if it does contain RAM at all.
+When using the "malloc" function combined with loading exe files, it may be
+recommended not to pass all memory to InitHeap (ie. to keep a memory region
+being reserved for loading executables).
+
+Note
+For more info about EXE files and their headers, see
+--> CDROM File Formats
+
+BIOS CDROM Functions
+--------------------
+
+General File Functions
+CDROMs are basically accessed via normal file functions, with device name
+"cdrom:" (which is an abbreviation for "cdrom0:", anyways, the port number is
+ignored).
+--> BIOS File Functions
+--> BIOS File Execute and Flush Cache
+Before starting the boot executable, the BIOS automatically calls CdInit(), so
+the game doesn't need to do any initializations before using CDROM file
+functions.
+
+Absent CD-Audio Support
+The Kernel doesn't include any functions for playing Audio tracks. Also,
+there's no BIOS function for setting the XA-ADPCM file/channel filter values.
+So CD Audio can be used only by directly programming the CDROM I/O ports.
+
+Asynchronous CDROM Access
+The normal File functions are always using synchroneous access for CDROM (ie.
+the functions do wait until all data is transferred) (unlike as for memory
+cards, accessmode.bit15 cannot be used to activate asynchronous cdrom access).
+However, one can read files in asynchrouneous fashion via CdGetLbn,
+CdAsyncSeekL, and CdAsyncReadSector. CDROM files are non-fragmented, so they
+can be read simply from incrementing sector numbers.
+
+A(A4h) - CdGetLbn(filename)
+Returns the first sector number used by the file, or -1 in case of error.
+BUG: The function accidently returns -1 for the first file in the directory
+(the first file should be a dummy entry for the current or parent directory or
+so, so that bug isn't much of a problem), if the file is not found, then the
+function accidently returns garbage (rather than -1).
+
+A(A5h) - CdReadSector(count,sector,buffer)
+Reads <count> sectors, starting at <sector>, and writes data to <buffer>. The
+read is done in mode=80h (double speed, 800h-bytes per sector). The function
+waits until all sectors are transferred, and does then return the number of
+sectors (ie. count), or -1 in case of error.
+
+A(A6h) - CdGetStatus()
+Retrieves the cdrom status via CdAsyncGetStatus(dst) (see there for details;
+especially for cautions on door-open flag). The function waits until the event
+indicates completion, and does then return the status byte (or -1 in case of
+error).
+
+A(78h) - CdAsyncSeekL(src)
+Issues Setloc and SeekL commands. The parameter (src) is a pointer to a 3-byte
+sector number (MM,SS,FF) (in BCD format).
+The function returns 0=failed, or 1=okay. Completion is indicated by events
+(class=F0000003h, and spec=20h, or 8000h).
+
+A(7Ch) - CdAsyncGetStatus(dst)
+Issues a GetStat command. The parameter (dst) is a pointer to a 1-byte location
+that receives the status response byte.
+The function returns 0=failed, or 1=okay. Completion is indicated by events
+(class=F0000003h, and spec=20h, or 8000h).
+Caution: The command acknowledges the door-open flag, but doesn't automatically
+reload the path table (which is required if a new disk is inserted); if the
+door-open flag was set, one should call a function that does forcefully load
+the path table (like chdir).
+
+A(7Eh) - CdAsyncReadSector(count,dst,mode)
+Issues SetMode and ReadN (when mode.bit8=0), or ReadS (when mode.bit8=1)
+commands. count is the number of sectors to be read, dst is the destination
+address in RAM, mode.bit0-7 are passed as parameter to the SetMode command,
+mode.bit8 is the ReadN/ReadS flag (as described above). The sector size (for
+DMA) depends on the mode value: 918h-bytes (bit4=1, bit5=X), 924h-bytes
+(bit4=0, bit5=1), or 800h-bytes (bit4,5=0).
+Before CdAsyncReadSector, the sector number should be set via
+CdAsyncSeekL(src).
+The function returns 0=failed, or 1=okay. Completion is indicated by events
+(class=F0000003h, and spec=20h, 80h, or 8000h).
+
+A(81h) - CdAsyncSetMode(mode)
+Similar to CdAsyncReadSector (see there for details), but issues only the
+SetMode command, without any following ReadN/ReadS command.
+
+A(94h) - CdromGetInt5errCode(dst1,dst2)
+Returns the first two response bytes from the most recent INT5 error:
+[dst1]=status, [dst2]=errorcode. The BIOS doesn't reset these values in case of
+successful completion, so the values are quite useless.
+
+A(54h) or A(71h) - CdInit()
+A(56h) or A(72h) - CdRemove()
+A(90h) - CdromIoIrqFunc1()
+A(91h) - CdromDmaIrqFunc1()
+A(92h) - CdromIoIrqFunc2()
+A(93h) - CdromDmaIrqFunc2()
+A(95h) - CdInitSubFunc() ;subfunction for CdInit()
+A(9Eh) - SetCdromIrqAutoAbort(type,flag)
+A(A2h) - EnqueueCdIntr() ;with prio=0 (fixed)
+A(A3h) - DequeueCdIntr()
+Internally used CDROM functions for initialization and IRQ handling.
+
+BIOS Memory Card Functions
+--------------------------
+
+General File Functions
+Memory Cards aka Backup Units (bu) are basically accessed via normal file
+functions, with device names "bu00:" (Slot 1) and "bu10:" (Slot 2),
+--> BIOS File Functions
+Before using the file functions for memory cards, first call
+InitCard(pad_enable), then StartCard(), and then _bu_init().
+
+File Header, Filesize, and Sector Alignment
+The first 100h..200h bytes (2..4 sectors) of the file must contain the title
+and icon bitmap(s). For details, see:
+--> Memory Card Data Format
+The filesize must be a multiple of 2000h bytes (one block), the maximum size
+would be 1E000h bytes (when using all 15 blocks on the memory card). The
+filesize must be specified when creating the file (ie. accessmode bit9=1, and
+bit16-31=number of blocks). Once when the file is created, the BIOS does NOT
+allow to change the filesize (unless by deleting and re-creating the file).
+When reading/writing files, the amount of data must be a multiple of 80h bytes
+(one sector), and the file position must be aligned to a 80h-byte boundary,
+too. There's no restriction on fragmented files (ie. one may cross 2000h-byte
+block boundaries within the file).
+
+Poor Memcard Performance
+PSX memory card accesses are typically super-slow. That, not so much because
+the hardware would be slow, but rather because of improper inefficent code at
+the BIOS side. The original BIOS tries to synchronize memory card accesses with
+joypad accesses simply by accessing only one sector per frame (although it
+could access circa two sectors). To the worst, the BIOS accesses Slot 1 only on
+each second frame, and Slot 2 only each other frame (although in 99% of all
+cases only one slot is accessed at once, so the access time drops to 0.5
+sectors per frame).
+Moreover, the memory card id, directory, and broken sector list do occupy 26
+sectors (although the whole information would fit into 4 or 5 sectors) (a
+workaround would be to read only the first some bytes, and to skip the
+additional unused bytes - though that'd also mean to skip the checksums which
+are unfortunately stored at the end of the sector).
+And, anytime when opening a file (in synchronous mode), the BIOS does
+additionally read sector 0 (which is totally useless, and gets especially slow
+when opening a bunch of files; eg. when extracting the title/icon from all
+available files on the card).
+
+Asynchronous Access
+The BIOS supports synchronous and asynchronous memory card access. Synchronous
+means that the BIOS function doesn't return until the access has completed
+(which means, due to the poor performance, that the function spends about 75%
+of the time on inactivity) (except in nocash PSX bios, which has better
+performance), whilst asynchronous access means that the BIOS function returns
+immediately after invoking the access (which does then continue on interrupt
+level, and does return an event when finished).
+The file "FileRead" and "FileWrite" functions act asynchronous when accessmode
+bit15 is set when opening the file. Additionally, the A(ACh)
+_card_async_load_directory(port) function can be used to tell the BIOS to load
+the directory entries and broken sector list to its internal RAM buffers (eg.
+during the games title screen, so the BIOS doesn't need to load that data once
+when the game enters its memory card menu). All other functions like FileDelete
+or FormatDevice always act synchronous. The FileOpen/findfirst/findnext
+functions do normally complete immediately without accessing the card at all
+(unless the directory wasn't yet read; in that case the directory is loading in
+synchronous fashion).
+Unfortunately, the asynchronous response doesn't rely on a single callback
+event, but rather on a bunch of different events which must be all allocated
+and tested by the game (and of which, one event is delivered on completion)
+(which one depends on whether function completed okay, or if an error
+occurred).
+
+Multitap Support (and Multitap Problems)
+The BIOS does have some partial support for accessing more than two memory
+cards (via Multitap adaptors). Device/port names "bu01:", "bu02:", "bu03:"
+allow to access extra memory carts in slot1 (and "bu11:", "bu12:", "bu13:" in
+slot2). Namely, those names will send values 82h, 83h, 84h to the memory card
+slot (instead of the normal 81h value).
+However, the BIOS directory_buffer and broken_sector_list do support only two
+memory cards (one in slot1 and one in slot2). So, trying to access more memory
+cards may cause great data corruption (though there might be a way to get the
+BIOS to reload those buffers before accessing a different memory card).
+Aside from that problem, the BIOS functions are very-very-very slow even when
+accessing only two memory cards. Trying to use the BIOS to access up to eight
+memory cards would be very-extremly-very slow, which would be more annoying
+than useful.
+
+B(4Ah) - InitCard(pad_enable) ;uses/destroys k0/k1 !!!
+B(4Bh) - StartCard()
+B(4Ch) - StopCard()
+A(55h) or A(70h) - _bu_init()
+
+ --- Below are some lower level memory card functions ---
+
+A(ABh) - _card_info(port)
+B(4Dh) - _card_info_subfunc(port) ;subfunction for "_card_info"
+Can be used to check if the most recent call to write_card_sector has completed
+okay. Issues an incomplete dummy read command (similar to B(4Fh) -
+read_card_sector). The read command is aborted once when receiving the status
+byte from the memory card (the actual data transfer is skipped).
+
+A(AFh) - card_write_test(port) ;not supported by old CEX-1000 version
+Resets the card changed flag. For some strange reason, this flag isn't
+automatically reset after reading the flag, instead, the flag is reset upon
+sector writes. To do that, this function issues a dummy write to sector 3Fh.
+
+B(50h) - allow_new_card()
+Normally any memory card read/write functions fail if the BIOS senses the card
+change flag to be set. Calling this function tells the BIOS to ignore the card
+change flag on the next read/write operation (the function is internally used
+when loading the "MC" ID from sector 0, and when calling the card_write_test
+function to acknowledge the card change flag).
+
+B(4Eh) - write_card_sector(port,sector,src)
+B(4Fh) - read_card_sector(port,sector,dst)
+Invokes asynchronous reading/writing of a single sector. The function returns
+1=okay, or 0=failed (on invalid sector numbers). The actual I/O is done on IRQ
+level, completion of the I/O command transmission can be checked, among others,
+via get/wait_card_status(slot) functions (with slot=port/10h).
+In case of the write function, completion of the <transmission> does NOT mean
+that the actual <writing> has completed, instead, write errors are indicated
+upon completion of the <next sector> read/write transmission (or, if there are
+no further sectors to be accessed; one can use _card_info to verify completion
+of the last written sector).
+The sector number should be in range of 0..3FFh, for some strange reason,
+probably a BUG, the function also accepts sector 400h. The specified sector
+number is directly accessed (it is NOT parsed through the broken sector
+replacement list).
+
+B(5Ch) - get_card_status(slot)
+B(5Dh) - wait_card_status(slot)
+Returns the status of the most recent I/O command, possible values are:
+ 01h=ready
+ 02h=busy/read
+ 04h=busy/write
+ 08h=busy/info
+ 11h=failed/timeout (eg. when no cartridge inserted)
+ 21h=failed/general error
+get_card_status returns immediately, wait_card_status waits until a non-busy
+state occurs.
+
+A(A7h) - bu_callback_okay()
+A(A8h) - bu_callback_err_write()
+A(A9h) - bu_callback_err_busy()
+A(AAh) - bu_callback_err_eject()
+A(AEh) - bu_callback_err_prev_write()
+These five callback functions are internally used by the BIOS, notifying other
+BIOS functions about (un-)successful completion of memory card I/O commands.
+
+B(58h) - get_bu_callback_port()
+This is a subfunction for the five bu_callback_xxx functions (indicating
+whether the callback occured for a slot1 or slot2 access).
+
+A(ACh) - _card_async_load_directory(port)
+Invokes asynchronous reading of the memory card directory. The function isn't
+too useful because the BIOS tends to read the directory automatically in
+various places in synchronous mode, so there isn't too much chance to replace
+the automatic synchronous reading by asynchronous reading.
+
+A(ADh) - set_card_auto_format(flag)
+Can be used to enable/disable auto format (0=off, 1=on). The _bu_init function
+initializes auto format as disabled. If auto format is enabled, then the BIOS
+does automatically format memory cards if it has failed to read the "MC" ID
+bytes on sector 0. Although potentially useful, activating this feature is
+rather destructive (for example, read errors on sector 0 might occur accidently
+due to improperly inserted cards with dirty contacts, so it'd be better to
+prompt the user whether or not to format the card, rather than doing that
+automatically).
+
+C(1Ah) - set_card_find_mode(mode)
+C(1Dh) - get_card_find_mode()
+Allows to get/set the card find mode (0=normal, 1=find deleted files), the mode
+setting affects only the firstfile/nextfile functions. All other file functions
+are used fixed mode settings (always mode=0 for FileOpen, FileRename,
+FileDelete, and mode=1 for FileUndelete).
+
+BIOS Interrupt/Exception Handling
+---------------------------------
+
+The Playstation's Kernel uses an uncredible inefficient and unstable exception
+handler; which may have been believed to be very powerful and flexible.
+
+Inefficiency
+For a maximum of slowness, it does always save and restore all CPU registers
+(including such that aren't used in the exception handler). It does then go
+through a list of installed interrupt handlers - and executes ALL of them. For
+example, a Timer0 IRQ is first passed to the Cdrom and Vblank handlers (which
+must reject it, no thanks), before it does eventually reach the Timer0 handler.
+
+Unstable IRQ Handling
+A fundamental mistake in the exception handler is that it doesn't memorize the
+incoming IRQ flags. So the various interrupt handlers must check Port 1F801070h
+one after each other. That means, if a high priority handler has rejected IRQ
+processing (because the desired IRQ flag wasn't set at that time), then a lower
+priority handler may process it (assuming that the IRQ flag got set in the
+meantime), and, in worst case it may even acknowledge it (so the high priority
+handler does never receive it).
+To avoid such problems, there should be only ONE handler installed for each IRQ
+source. However, that isn't always possible because the Kernel automatically
+installs some predefined handlers. Most noteworthy, the totally bugged
+DefaultInterruptHandlers is always installed (and cannot be removed), so it
+does randomly trigger Events. Fortunately, it does not acknowledge the IRQs
+(unless SetIrqAutoAck was used to enable that fatal behaviour).
+
+B(18h) - SetDefaultExitFromException()
+Applies the default "Exit" structure (which consists of a pointer to
+ReturnFromException, and the Kernel's exception stacktop (minus 4, for whatever
+reason), and zeroes for the R16..R23,R28,R30 registers. Returns the address of
+that structure.
+See SetCustomExitFromException for details.
+
+B(19h) - SetCustomExitFromException(addr)
+addr points to a structure (with same format as for the SaveState function):
+ 00h 4 r31/ra,pc ;usually ptr to ReturnFromException function
+ 04h 4 r28/sp ;usually exception stacktop, minus 4, for whatever reason
+ 08h 4 r30/fp ;usually 0
+ 0Ch 4x8 r16..r23 ;usually 0
+ 2Ch 4 r28/gp ;usually 0
+The hook function is executed only if the ExceptionHandler has been fully
+executed (after processing an IRQ, many interrupt handlers are calling
+ReturnFromException to abort further exception handling, and thus do skip the
+hook function). Once when the hook function has finished, it should execute
+ReturnFromException. The hook function is called with r2=1 (that is important
+if the hook address was recorded with SaveState, where it "returns" to the
+SaveState caller, with r2 as "return value").
+
+Priority Chains
+The Kernel's exception handler has four priority chains, each may contain one
+or more Interrupt or Exception handlers. The default handlers are:
+ Prio Chain Content
+ 0 CdromDmaIrq, CdromIoIrq, SyscallException
+ 1 CardSpecificIrq, VblankIrq, Timer2Irq, Timer1Irq, Timer0Irq
+ 2 PadCardIrq
+ 3 DefInt
+The exception handler calls all handlers, starting with the first element in
+the priority 0 chain (ie. usually CdromDmaIrq). The separate handlers must
+check if they want to process the IRQ (eg. CdromDmaIrq would process only CDROM
+DMA IRQs, but not joypad IRQs or so). If it has processed and acknowledged the
+IRQ, then the handler may execute ReturnFromException, which causes the
+handlers of lower priority to be skipped (if there are still other
+unacknowledge IRQs pending, then the hardware will re-enter the exception
+handler as soon as the RFE opcode in ReturnFromException does re-enable
+interrupts).
+
+C(02h) - SysEnqIntRP(priority,struc)
+Inserts a new element in the specified priority chain. The new element is
+inserted at the begin of the chain, so (within that priority chain) the new
+element has highest priority.
+ 00h 4 pointer to next element (0=none) ;this pointer is inserted by BIOS
+ 04h 4 pointer to SECOND function (0=none) ;executed if func1 returns r2<>0
+ 08h 4 pointer to FIRST function (0=none) ;executed first
+ 0Ch 4 Not used (usually zero)
+
+XXX...
+The BIOS seems to be occassionally adding/removing the "CardSpecificIrq" and
+"PadCardIrq" (with priority 1 and 2). DequeueCdIntr and CdRemove remove
+priority 0 elements.
+
+C(03h) - SysDeqIntRP(priority,struc)
+Removes the specified element from the specified priority chain. Returns
+r2=struc (or 0 if the struc didn't exist in the chain).
+Note: The function contains several nonsense opcodes that are never executed
+(they are skipped via conditional jumps with fixed "jump always" condition).
+
+SYS(01h) - EnterCriticalSection() ;syscall with r4=01h
+Disables interrupts by clearing SR (cop0r12) Bit 2 and 10 (of which, Bit2 gets
+copied to Bit0 once when returning from the syscall exception). Returns 1 if
+both bits were set, returns 0 if one or both of the bits were already zero.
+
+SYS(02h) - ExitCriticalSection() ;syscall with r4=02h
+Enables interrupts by set SR (cop0r12) Bit 2 and 10 (of which, Bit2 gets copied
+to Bit0 once when returning from the syscall exception). There's no return
+value (all registers except SR and K0 are unchanged).
+
+C(0Dh) - SetIrqAutoAck(irq,flag)
+Specifies if the DefaultInterruptHandler shall automatically acknowledge IRQs.
+The "irq" paramter is the number of the interrupt, ie. 00h..0Ah = IRQ0..IRQ10.
+The "flag" value should be 0 to disable AutoAck, or non-zero to enable AutoAck.
+By default, AutoAck is disabled for all IRQs.
+Mind that the DefaultInterruptHandler is totally bugged. Especially the AutoAck
+feature doesn't work very well: It may cause higher priority handlers to miss
+their IRQ, and it may even cause the DefaultInterruptHandler to miss its own
+IRQs.
+
+C(06h) - ExceptionHandler()
+The C(06h) vector points to the exception handler, ie. to the function that is
+invoked from the 4 opcodes at address 80000080h, that opcodes jump directly to
+the exception handler, so patching the C(06h) vector has no effect.
+Reading the C(06h) entry can be used to let a custom 80000080h handler pass
+control back to the default handler (that, by a "direct" jump, not by the usual
+"MOV R9,06h / CALL 0C0h" method, which would destroy main programs R9
+register).
+Also, reading C(06h) may be useful for patching the exception handler (which
+contains a bunch of NOP opcodes, which seem to be intended to insert additional
+opcodes, such like debugger exception handling) (Note: some of that NOPs are
+reserved for Memory Card IRQ handling).
+BUG: Early BIOS versions did try to examine a copy of cop0r13 in r2 register,
+but did forgot cop0r13 to r2 (so they examined garbage), this was fixed in
+newer BIOS versions, additionally, most commercial games still include patches
+for compatibility with the old BIOS.
+
+B(17h) - ReturnFromException()
+Restores the CPU registers (R1-R31,HI,LO,SR,PC) (except R26/K0) from the
+current TCB. This function is usually executed automatically at the end of the
+ExceptionHandler, however, functions in the exception chain may call
+ReturnFromException to return immediately, without processing chain elements of
+lower priority.
+
+C(00h) - EnqueueTimerAndVblankIrqs(priority) ;used with prio=1
+C(01h) - EnqueueSyscallHandler(priority) ;used with prio=0
+C(0Ch) - InitDefInt(priority) ;used with prio=3
+Internally used to add some default IRQ and Exception handlers.
+
+No Nested Exceptions
+The Kernel doesn't support nested exceptions, that would require a decreasing
+exception stack, however, the kernel saves the incoming CPU registers in the
+current TCB, and an exception stack with fixed start address for internal
+push/pop during exception handling. So, nesting would overwrite these values.
+Do not enable IRQs, and don't trap other exceptions (like break or syscall
+opcodes, or memory or overlow errors) during exception handling.
+Note: The execption stack has a fixed size of 1000h bytes (and is located
+somewhere in the first 64Kbytes of memory).
+
+BIOS Event Functions
+--------------------
+
+B(08h) - OpenEvent(class, spec, mode, func)
+Adds an event structure to the event table.
+ class,spec - triggers if BOTH values match
+ mode - (1000h=execute function/stay busy, 2000h=no func/mark ready)
+ func - Address of callback function (0=None) (used only when mode=1000h)
+ out: R2 = Event descriptor (F1000000h and up), or FFFFFFFFh if failed
+Opens an event, should be called within a critical section. The return value is
+used to identify the event to the other event functions. A list of event
+classes, specs and modes is at the end of this section. Initially, the event is
+disabled.
+Note: The desired max number of events can be specified in the SYSTEM.CNF boot
+file (the default is "EVENT = 10" (which is a HEX number, ie. 16 decimal; of
+which 5 events are internally used by the BIOS for CDROM functions, so, of the
+16 events, only 11 events are available to the game). A bigger amount of events
+will slowdown the DeliverEvent function (which always scans all EvCBs, even if
+all events are disabled).
+
+B(09h) - CloseEvent(event) - releases event from the event table
+Always returns 1 (even if the event handle is unused or invalid).
+
+B(0Ch) - EnableEvent(event) - Turns on event handling for specified event
+Always returns 1 (even if the event handle is unused or invalid).
+
+B(0Dh) - DisableEvent(event) - Turns off event handling for specified event
+Always returns 1 (even if the event handle is unused or invalid).
+
+B(0Ah) WaitEvent(event)
+Returns 0 if the event is disabled. Otherwise hangs in a loop until the event
+becomes ready, and returns 1 once when it is ready (and automatically switches
+the event back to busy status). Callback events (mode=1000h) do never set the
+ready flag (and thus WaitEvent would hang forever).
+The main program simply hangs during the wait, so when using multiple threads,
+it may be more recommended to create an own waitloop that checks TestEvent, and
+to call ChangeThread when the event is busy.
+BUG: The return value is unstable (sometimes accidently returns 0=disabled if
+the event status changes from not-ready to ready shortly after the function
+call).
+
+B(0Bh) TestEvent(event)
+Returns 0 if the event is busy or disabled. Otherwise, when it is ready,
+returns 1 (and automatically switches the event back to busy status). Callback
+events (mode=1000h) do never set the ready flag.
+
+B(07h) DeliverEvent(class, spec)
+This function is usually called by the kernel, it triggers all events that are
+enabled/busy, and that have the specified class and spec values. Depending on
+the mode, either the callback function is called (mode=1000h), or the event is
+marked as enabled/ready (mode=2000h).
+
+B(20h) UnDeliverEvent(class, spec)
+This function is usually called by the kernel, undelivers all events that are
+enabled/ready, and that have mode=2000h, and that have the specified class and
+spec values. Undeliver means that the events are marked as enabled/busy.
+
+C(04h) get_free_EvCB_slot()
+A subfunction for OpenEvent.
+
+Event Classes
+File Events:
+ 0000000xh memory card (for file handle fd=x)
+Hardware Events:
+ F0000001h IRQ0 VBLANK
+ F0000002h IRQ1 GPU
+ F0000003h IRQ2 CDROM Decoder
+ F0000004h IRQ3 DMA controller
+ F0000005h IRQ4 RTC0 (timer0)
+ F0000006h IRQ5/IRQ6 RTC1 (timer1 or timer2)
+ F0000007h N/A Not used (this should be timer2)
+ F0000008h IRQ7 Controller (joypad/memcard)
+ F0000009h IRQ9 SPU
+ F000000Ah IRQ10 PIO ;uh, does the PIO have an IRQ signal? (IRQ10 is joypad)
+ F000000Bh IRQ8 SIO
+ F0000010h Exception ;CPU crashed (BRK,BadSyscall,Overflow,MemoryError, etc.)
+ F0000011h memory card (lower level BIOS functions)
+ F0000012h memory card (not used by BIOS; maybe used by Sony's devkit?)
+ F0000013h memory card (not used by BIOS; maybe used by Sony's devkit?)
+Event Events:
+ F1xxxxxxh event (not used by BIOS; maybe used by Sony's devkit?)
+Root Counter Events (Timers and Vblank):
+ F2000000h Root counter 0 (Dotclock) (hardware timer)
+ F2000001h Root counter 1 (horizontal retrace?) (hardware timer)
+ F2000002h Root counter 2 (one-eighth of system clock) (hardware timer)
+ F2000003h Root counter 3 (vertical retrace?) (this is a software timer)
+User Events:
+ F3xxxxxxh user (not used by BIOS; maybe used by games and/or Sony's devkit?)
+BIOS Events (including such that have nothing to do with BIOS):
+ F4000001h memory card (higher level BIOS functions)
+ F4000002h libmath (not used by BIOS; maybe used by Sony's devkit?)
+Thread Events:
+ FFxxxxxxh thread (not used by BIOS; maybe used by Sony's devkit?)
+
+Event Specs
+ 0001h counter becomes zero
+ 0002h interrupted
+ 0004h end of i/o
+ 0008h file was closed
+ 0010h command acknowledged
+ 0020h command completed
+ 0040h data ready
+ 0080h data end
+ 0100h time out
+ 0200h unknown command
+ 0400h end of read buffer
+ 0800h end of write buffer
+ 1000h general interrupt
+ 2000h new device
+ 4000h system call instruction ;SYS(04h..FFFFFFFFh)
+ 8000h error happened
+ 8001h previous write error happened
+ 0301h domain error in libmath
+ 0302h range error in libmath
+
+Event modes
+ 1000h Execute callback function, and stay busy (do NOT mark event as ready)
+ 2000h Do NOT execute callback function, and mark event as ready
+
+BIOS Event Summary
+------------------
+
+Below is a list of all events (class,spec values) that are delivered and/or
+undelivered by the BIOS in one way or another. The BIOS does internally open
+five events for cdrom (class=F0000003h with spec=10h,20h,40h,80h,8000h). The
+various other class/spec's are only delivered by the BIOS (but not received by
+the BIOS) (ie. a game may open/enable memory card events to receive
+notifications from the BIOS).
+
+CDROM Events
+ F0000003h,10h cdrom DMA finished (all sectors finished)
+ F0000003h,20h cdrom ?
+ F0000003h,40h cdrom dead feature (delivered only by unused functions)
+ F0000003h,80h cdrom INT4 (reached end of disk)
+ F0000003h,100h n/a ? ;undelivered, but not opened, nor delivered
+ F0000003h,200h ;undelivered, but not opened
+ F0000003h,8000h
+
+Memory Card - Higher Level File/Device Events
+ 0000000xh,4 card file handle (x=fd) done okay
+ F4000001h,4 card done okay (len=0)
+ F4000001h,100h card err busy ;A(A9h)
+ F4000001h,2000h card err eject ;A(AAh) or unformatted (bad "MC" id)
+ F4000001h,8000h card err write ;A(A8h) or A(AEh) or general error
+
+Memory Card - Lower Level Hardware I/O Events
+ F0000011h,4 finished okay
+ F0000011h,100h err busy
+ F0000011h,200h n/a ?
+ F0000011h,2000h err
+ F0000011h,8000h err
+ F0000011h,8001h err (this one is NOT undelivered!)
+
+Timer/Vblank Events
+ F2000000h,2 Timer0 (IRQ4)
+ F2000001h,2 Timer1 (IRQ5)
+ F2000002h,2 Timer2 (IRQ6)
+ F2000003h,2 Vblank (IRQ0) (unstable since IRQ0 is also used for joypad)
+
+Default IRQ Handler Events (very unstable, don't use)
+ F0000001h,1000h ;IRQ0 (VBLANK)
+ F0000002h,1000h ;IRQ1 (GPU)
+ F0000003h,1000h ;IRQ2 (CDROM)
+ F0000004h,1000h ;IRQ3 (DMA)
+ F0000005h,1000h ;IRQ4 (TMR0)
+ F0000006h,1000h ;IRQ5 (TMR1)
+ F0000006h,1000h ;IRQ6 (TMR2) (accidently uses same event as TMR1)
+ F0000008h,1000h ;IRQ7 (joypad/memcard)
+ F0000009h,1000h ;IRQ9 (SPU)
+ F000000Ah,1000h ;IRQ10 (Joypad and PIO)
+ F000000Bh,1000h ;IRQ8 (SIO)
+
+Unresolved Exception Events
+ F0000010h,1000h unknown exception ;neither IRQ nor SYSCALL
+ F0000010h,4000h unknown syscall ;syscall(04h..FFFFFFFFh)
+
+BIOS Thread Functions
+---------------------
+
+B(0Eh) OpenThread(reg_PC,reg_SP_FP,reg_GP)
+Searches a free TCB, marks it as used, and stores the inital program counter
+(PC), global pointer (GP aka R28), stack pointer (SP aka R29), and frame
+pointer (FP aka R30) (using the same value for SP and FP). All other registers
+are left uninitialized (eg. may contain values from an older closed thread,
+that includes the SR register, see note).
+The return value is the new thread handle (in range FF000000h..FF000003h,
+assuming that 4 TCBs are allocated) or FFFFFFFFh if there's no free TCB. The
+function returns to the old current thread, use "ChangeThread" to switch to the
+new thread.
+Note: The desired max number of TCBs can be specified in the SYSTEM.CNF boot
+file (the default is "TCB = 4", one initially used for the boot executable,
+plus 3 free threads).
+
+BUG - Unitialized SR Register
+OpenThread does NOT initialize the SR register (cop0r12) of the new thread.
+Upon powerup, the bootcode zerofills the TCB memory (so, the SR of new threads
+will be initially zero; ie. Kernel Mode, IRQ's disabled, and COP2 disabled).
+However, when closing/reopening threads, the SR register will have the value of
+the old closed thread (so it may get started with IRQs enabled, and, in worst
+case, if the old thread should have switched to User Mode, even without access
+to KSEG0, KSEG1 memory).
+Or, ACTUALLY, the memory is NOT zerofilled on powerup... so SR is total random?
+
+B(0Fh) CloseThread(handle)
+Marks the TCB for the specified thread as unused. The function can be used for
+any threads, including for the current thread.
+Closing the current thread doesn't terminate the current thread, so it may
+cause problems once when opening a new thread, however, it should be stable to
+execute the sequence "DisableInterrupts, CloseCurrentThread,
+ChangeOtherThread".
+The return value is always 1 (even if the handle was already closed).
+
+B(10h) ChangeThread(handle)
+Pauses the current thread, and activates the selected new thread (or crashes if
+the specified handle was unused or invalid).
+The return value is always 1 (stored in the R2 entry of the TCB of the old
+thread, so the return value will be received once when changing back to the old
+thread).
+Note: The BIOS doesn't automatically switch from one thread to another. So, all
+other threads remain paused until the current thread uses ChangeThread to pass
+control to another thread.
+Each thread is having it's own CPU registers (R1..R31,HI,LO,SR,PC), the
+registers are stored in the TCB of the old thread, and restored when switching
+back to that thread. Mind that other registers (I/O Ports or GTE registers
+aren't stored automatically, so, when needed, they need to be pushed/popped by
+software before/after ChangeThread).
+
+C(05h) get_free_TCB_slot()
+Subfunction for OpenThread, returns the number of the first free TCB (usually
+in range 0..3) or FFFFFFFFh if there's no free TCB.
+
+SYS(03h) ChangeThreadSubFunction(addr) ;syscall with r4=03h, r5=addr
+Subfunction for ChangeThread, R5 contains the address of the new TCB, just like
+all exceptions, the syscall exception is saving the CPU registers in the
+current TCB, but does then apply the new TCB as current TCB, and so, it does
+then enter the new thread when returning from the exception.
+
+BIOS Timer Functions
+--------------------
+
+Timers (aka Root Counters)
+The three hardware timers aren't internally used by any BIOS functions, so they
+can be freely used by the game, either via below functions, or via direct I/O
+access.
+
+Vblank
+Some of the below functions are allowing to use Vblank IRQs as a fourth
+"timer". However, Vblank IRQs are internally used by the BIOS for handling
+joypad and memory card accesses. One could theoretically use two separate
+Vblank IRQ handlers, one for joypad, and one as "timer", but the BIOS is much
+too unstable for such "shared" IRQ handling (it may occassionally miss one of
+the two handlers).
+So, although Vblank IRQs are most important for games, the PSX BIOS doesn't
+actually allow to use them for purposes other than joypad access. A possible
+workaround is to examine the status byte in one of the joypad buffers (ie. the
+InitPad(buf1,22h,buf2,22h) buffers). Eg. a wait_for_vblank function could look
+like so: set buf1[0]=55h, then wait until buf1[0]=00h or buf1[0]=FFh.
+
+B(02h) init_timer(t,reload,flags)
+When t=0..2, resets the old timer mode by setting [1F801104h+t*16]=0000h,
+applies the reload value by [1F801108h+t*16]=reload, computes the new mode:
+ if flags.bit4=0 then mode=0048h else mode=0049h
+ if flags.bit0=0 then mode=mode OR 100h
+ if flags.bit12=1 then mode=mode OR 10h
+and applies it by setting [1F801104h+t*16]=mode, and returns 1. Does nothing
+and returns zero for t>2.
+
+B(03h) get_timer(t)
+Reads the current timer value: Returns halfword[1F801100h+t*16] for t=0..2.
+Does nothing and returns zero for t>2.
+
+B(04h) enable_timer_irq(t)
+B(05h) disable_timer_irq(t)
+Enables/disables timer or vblank interrupt enable bits in [1F801074h], bit4,5,6
+for t=0,1,2, or bit0 for t=3, or random/garbage bits for t>3. The enable
+function returns 1 for t=0..2, and 0 for t=3. The disable function returns
+always 1.
+
+B(06h) restart_timer(t)
+Sets the current timer value to zero: Sets [1F801100h+t*16]=0000h and returns 1
+for t=0..2. Does nothing and returns zero for t>2.
+
+C(0Ah) - ChangeClearRCnt(t,flag) ;root counter (aka timer)
+Selects what the kernel's timer/vblank IRQ handlers shall do after they have
+processed an IRQ (t=0..2: timer 0..2, or t=3: vblank) (flag=0: do nothing; or
+flag=1: automatically acknowledge the IRQ and immediately return from
+exception). The function returns the old (previous) flag value.
+
+BIOS Joypad Functions
+---------------------
+
+Pad Input
+Joypads should be initialized via InitPad(buf1,22h,buf2,22h), and StartPad().
+The main program can read the pad data from the buf1/buf2 addresses (including
+Status, ID1, button states, and any kind of analogue inputs). For more info on
+ID1, Buttons and analogue inputs, see
+--> Controllers and Memory Cards
+Note: The BIOS doesn't include any functions for sending custom data to the
+pads (such like for controlling rumble motors).
+
+B(12h) - InitPad(buf1, siz1, buf2, siz2)
+Memorizes the desired buf1/buf2 addresses, zerofills the buffers by using the
+siz1/siz2 buffer size values (which should be 22h bytes each). And does some
+initialization on the PadCardIrq element (but doesn't enqueue it, that must be
+done by a following call to StartPad), and does set the "pad_enable_flag", that
+flag can be also set/cleared via InitCard(pad_enable), where it selects if the
+Pads are kept handled together with Memory Cards. buf1/buf2 are having the
+following format:
+ 00h Status (00h=okay, FFh=timeout/wrong ID2)
+ 01h ID1 (eg. 41h=digital_pad, 73h=analogue_pad, 12h=mouse, etc.)
+ 02h..21h Data (max 16 halfwords, depending on lower 4bit of ID1)
+Note: InitPad does initially zerofill the buffers, so, until the first IRQ is
+processed, the initial status is 00h=okay, with buttons=0000h (all buttons
+pressed), to fix that situation, change the two status bytes to FFh after
+calling InitPad (or alternately, reject ID1=00h).
+Once when the PadCardIrq is enqueued via StartPad, and while "pad_enable_flag"
+is set, the data for (both) Pad1 and Pad2 is read on Vblank interrupts, and
+stored in the buffers, the IRQ handler stores up to 22h bytes in the buffer
+(regardless of the siz1/siz2 values) (eg. a Multitap adaptor uses all 22h
+bytes).
+
+B(13h) - StartPad()
+Should be used after InitPad. Enqueues the PadCardIrq handler, and does
+additionally initialize some flags.
+
+B(14h) - StopPad()
+Dequeues the PadCardIrq handler. Note that this handler is also used for memory
+cards, so it'll "stop" cards, too.
+
+B(15h) - OutdatedPadInitAndStart(type, button_dest, unused, unused)
+This is an extremely bizarre and restrictive function - don't use! The function
+fails unless type is 20000000h or 20000001h (the type value has no other
+function). The function uses "buf1/buf2" addresses that are located somewhere
+"hidden" within the BIOS variables region, the only way to read from that
+internal buffers is to use the ugly "OutdatedPadGetButtons()" function. For
+some strange reason it FFh-fills buf1/buf2, and does then call
+InitPad(buf1,22h,buf2,22) (which does immediately 00h-fill the previously
+FFh-filled buffers), and does then call StartPad().
+Finally, it does memorize the "button_dest" address (see
+OutdatedPadGetButtons() for details on that value). The two unused parameters
+have no function, however, they are internally written back to the stack
+locations reserved for parameter 2 and 3, ie. at [SP+08h] and [SP+0Ch] on the
+caller's stack, so the function MUST be called with all four parameters
+allocated on stack. Return value is 2 (or 0 if type was disliked).
+
+B(16h) - OutdatedPadGetButtons()
+This is a very ugly function, using the internal "buf1/buf2" values from
+"OutdatedPadInitAndStart" and the "button_dest" value that was passed to that
+function.
+If "button_dest" is non-zero, then this function is automatically called by the
+PadCardIrq handler, and stores it's return value at [button_dest] (where it may
+be read by the main program). If "button_dest" is zero, then it isn't called
+automatically, and it <can> be called manually (with return value in R2),
+however, it does additionally write the return value to [button_dest], ie. to
+[00000000h] in this case, destroying that memory location.
+The return value itself is useless garbage: The lower 16bit contain the pad1
+buttons, the upper 16bit the pad2 buttons, of which, both values have reversed
+byte-order (ie. the first button byte in upper 8bit). The function works only
+with controller IDs 41h (digital joypad) and 23h (nonstandard device). For
+ID=23h, the halfword is ORed with 07C7h, and bit6,7 are then cleared if the
+analogue inputs are greater than 10h. For ID=41h the data is left intact. Any
+other ID values, or disconnected joypads, cause the halfword to be set to FFFFh
+(same as when no buttons are pressed), that includes newer analogue pads
+(unless they are switched to "digital" mode).
+
+BIOS GPU Functions
+------------------
+
+A(48h) - SendGP1Command(gp1cmd)
+Writes [1F801814h]=gp1cmd. There's no return value (r2 is left unchanged).
+
+A(49h) - GPU_cw(gp0cmd) ;send GP0 command word
+Calls gpu_sync(), and does then write [1F801810h]=gp0cmd. Returns the return
+value from the gpu_sync() call.
+
+A(4Ah) - GPU_cwp(src,num) ;send GP0 command word and parameter words
+Calls gpu_sync(), and does then copy "num" words from [src and up] to
+[1F801810h], src should usually point to a command word, followed by num-1
+parameter words. Transfer is done by software (without DMA). Always returns 0.
+
+A(4Bh) - send_gpu_linked_list(src)
+Transfer an OT via DMA. Calls gpu_sync(), and does then write
+[1F801814h]=4000002h, [1F8010F4h]=0, [1F8010F0h]=[1F8010F0h] OR 800h,
+[1F8010A0h]=src, [1F8010A4h]=0, [1F8010A8h]=1000401h. The function does
+additionally output a bunch of TTY status messages via printf. The function
+doesn't wait until the DMA is completed. There's no return value.
+
+A(4Ch) - gpu_abort_dma()
+Writes [1F8010A8h]=401h, [1F801814h]=4000000h, [1F801814h]=2000000h,
+[1F801814h]=1000000h. Ie. stops GPU DMA, and issues GP1(4), GP1(2), GP1(1).
+Returns 1F801814h, ie. the I/O address.
+
+A(4Dh) - GetGPUStatus()
+Reads [1F801814h] and returns that value.
+
+A(46h) - GPU_dw(Xdst,Ydst,Xsiz,Ysiz,src)
+Waits until GPUSTAT.Bit26 is set (unlike gpu_sync, which waits for Bit28), and
+does then [1F801810h]=A0000000h, [1F801810h]=YdstXdst, [1F801810h]=YsizXsiz,
+and finally transfers "N" words from [src and up] to [1F801810h], where "N" is
+"Xsiz*Ysiz/2". The data is transferred by software (without DMA) (by code
+executed in the uncached BIOS region with high waitstates, so the data transfer
+is very SLOW).
+Caution: If "Xsiz*Ysiz" is odd, then the last halfword is NOT transferred, so
+the GPU stays waiting for the last data value.
+Returns [SP+04h]=Ydst, [SP+08h]=Xsiz, [SP+0Ch]=Ysiz, [SP+10h]=src+N*4, and
+R2=src=N*4.
+
+A(47h) - gpu_send_dma(Xdst,Ydst,Xsiz,Ysiz,src)
+Calls gpu_sync(), writes [1F801810h]=A0000000h, [1F801814h]=4000002h,
+[1F8010F0h]=[1F8010F0h] OR 800h, [1F8010A0h]=src, [1F8010A4h]=N*10000h+10h
+(where N="Xsiz*Ysiz/32"), [1F8010A8h]=1000201h.
+Caution: If "Xsiz*Ysiz" is not a multiple of 32, then the last halfword(s) are
+NOT transferred, so the GPU stays waiting for that values.
+Returns R2=1F801810h, and [SP+04h]=Ydst, [SP+08h]=Xsiz, [SP+0Ch]=Ysiz.
+
+A(4Eh) - gpu_sync()
+If DMA is off (when GPUSTAT.Bit29-30 are zero): Waits until GPUSTAT.Bit28=1 (or
+until timeout).
+If DMA is on: Waits until D2_CHCR.Bit24=0 (or until timeout), and does then
+wait until GPUSTAT.Bit28=1 (without timeout, ie. may hang forever), and does
+then turn off DMA via GP1(04h).
+Returns 0 (or -1 in case of timeout, however, the timeout values are very big,
+so it may take a LOT of seconds before it returns).
+
+BIOS Memory Allocation
+----------------------
+
+A(33h) - malloc(size)
+Allocates size bytes on the heap, and returns the memory handle (aka the
+address of the allocated memory block). The address of the block is guaranteed
+to by aligned to 4-byte memory boundaries. Size is rounded up to a multiple of
+4 bytes. The address may be in KUSEG, KSEG0, or KSEG1, depending on the address
+passed to InitHeap.
+Caution: The BIOS (tries to) initialize the heap size to 0 bytes (actually it
+accidently overwrites that initial setting by garbage during relocation), so
+any call to malloc will fail, unless InitHeap has been used to initialize the
+address/size of the heap.
+
+A(34h) - free(buf)
+Deallocates the memory block. There's no return value, and no error checking.
+The function simply sets [buf-4]=[buf-4] OR 00000001h, so if buf is an invalid
+handle it may destroy memory at [buf-4], or trigger a memory exception (for
+example, when buf=0).
+
+A(37h) - calloc(sizx, sizy) ;SLOW!
+Allocates xsiz*ysiz bytes by calling malloc(xsiz*ysiz), and, unlike malloc, it
+does additionally zerofill the memory via SLOW "bzero" function. Returns the
+address of the memory block (or zero if failed).
+
+A(38h) - realloc(old_buf, new_size) ;SLOW!
+If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or
+0=failed). Else, if "new_size" is zero, executes free(old_buf), and returns
+r2=garbage. Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size),
+and free(old_buf), and returns r2=new_buf (or 0=failed).
+Caution: The bcopy function is SLOW, and realloc does accidently copy
+"new_size" bytes from old_buf, so, if the old_size was smaller than new_size
+then it'll copy whatever garbage data - in worst case, if it exceeds the top of
+the 2MB RAM region, it may crash with a locked memory exception, although
+that'd happen only if SetMemSize(2) was used to restrict RAM to 2MBs.
+
+A(39h) - InitHeap(addr, size)
+Initializes the address and size of the heap - the BIOS does not automatically
+do this, so, before using the heap, InitHeap must be called by software.
+Usually, the heap would be memory region between the end of the boot
+executable, and the bottom of the executable's stack. InitHeap can be also used
+to deallocate all memory handles (eg. when a new exe file has been loaded, it
+may use it to deallocate all old memory).
+The heap is used only by malloc/realloc/calloc/free, and by the "qsort"
+function.
+
+B(00h) alloc_kernel_memory(size)
+B(01h) free_kernel_memory(buf)
+Same as malloc/free, but, instead of the heap, manages the 8kbyte control block
+memory at A000E000h..A000FFFFh. This region is used by the kernel to allocate
+ExCBs (4x08h bytes), EvCBs (N*1Ch bytes), TCBs (N*0C0h bytes), and the process
+control block (1x04h bytes). Unlike the heap, the BIOS does automatically
+initialize this memory region via SysInitMemory(addr,size), and does
+autimatically allocate the above data (where the number of EvCBs and TCBs is as
+specified in the SYSTEM.CNF file). Note: FCBs and DCBs are located elsewhere,
+at fixed locations in the kernel variables area.
+
+Scratchpad Note
+The kernel doesn't include any allocation functions for the scratchpad (nor do
+any kernel functions use that memory area), so the executable can freely use
+the "fast" memory at 1F800000h..1F8003FFh.
+
+A(9Fh) - SetMemSize(megabytes)
+Changes the effective RAM size (2 or 8 megabytes) by manipulating port
+1F801060h, and additionally stores the size in megabytes in RAM at [00000060h].
+Note: The BIOS bootcode accidently sets the RAM value to 2MB (which is the
+correct physical memory size), but initializes the I/O port to 8MB (which
+mirrors the physical 2MB within that 8MB region), so the initial values don't
+match up with each other.
+Caution: Applying the correct size of 2MB may cause the "realloc" function to
+crash (that function may accidently access memory above 2MB).
+
+BIOS Memory Fill/Copy/Compare (SLOW)
+------------------------------------
+
+Like most A(NNh) functions, below functions are executed in uncached BIOS ROM,
+the ROM has very high waitstates, and the 32bit opcodes are squeezed through an
+8bit bus. Moreover, below functions are restricted to process the data
+byte-by-byte. So, they are very-very-very slow, don't even think about using
+them.
+Of course, that applies also for most other BIOS functions. But it's becoming
+most obvious for these small functions; memcpy takes circa 160 cycles per byte
+(reasonable would be less than 4 cycles), and bzero takes circa 105 cycles per
+byte (reasonable would be less than 1 cycles).
+
+A(2Ah) - memcpy(dst, src, len)
+Copies len bytes from [src..src+len-1] to [dst..dst+len-1]. Refuses to copy any
+data when dst=00000000h or when len>7FFFFFFFh. The return value is always the
+incoming "dst" value.
+
+A(2Bh) - memset(dst, fillbyte, len)
+Fills len bytes at [dst..dst+len-1] with the fillbyte value. Refuses to fill
+memory when dst=00000000h or when len>7FFFFFFFh. The return value is the
+incoming "dst" value (or zero, when len=0 or len>7FFFFFFFh).
+
+A(2Ch) - memmove(dst, src, len) - bugged
+Same as memcpy, but (attempts) to support overlapping src/dst regions, by using
+a backwards transfer when src<dst (and, for some reason, only when
+dst>=src+len).
+BUG: The backwards variant accidently transfers len+1 bytes from [src+len..src]
+down to [dst+len..dst].
+
+A(2Dh) - memcmp(src1, src2, len) - bugged
+Compares len bytes at [src1..src1+len-1] with [src2..src2+len-1], and
+(attempts) to return the difference between the first mismatching bytes, ie.
+[src1+N]-[src2+N], or 0 if there are no mismatches. Refuses to compare data
+when src1 or src2 is 00000000h, and returns 0 in that case.
+BUG: Accidently returns the difference between the bytes AFTER the first
+mismatching bytes, ie. [src1+N+1]-[src2+N+1].
+That means that a return value of 0 can mean absolutely anything: That the
+memory blocks are identical, or that a mismatch has been found (but that the
+NEXT byte after the mismatch does match), or that the function has failed (due
+to src1 or src2 being 00000000h).
+
+A(2Eh) - memchr(src, scanbyte, len)
+Scans [src..src+len-1] for the first occurence of scanbyte. Refuses to scan any
+data when src=00000000h or when len>7FFFFFFFh. Returns the address of that
+first occurence, or 0 if the scanbyte wasn't found.
+
+A(27h) - bcopy(src, dst, len)
+Same as "memcpy", but with "src" and "dst" exchanged. That is, the first
+parameter is "src", the refuse occurs when "src" is 00000000h, and, returns the
+incoming "src" value (whilst "memcpy" uses "dst" in that places).
+
+A(28h) - bzero(dst, len)
+Same as memset, but uses 00h as fixed fillbyte value.
+
+A(29h) - bcmp(ptr1, ptr2, len) - bugged
+Same as "memcmp", with exactly the same bugs.
+
+BIOS String Functions
+---------------------
+
+A(15h) - strcat(dst, src)
+Appends src to the end of dst. Searches the ending 00h byte in dst, and copies
+src to that address, up to including the ending 00h byte in src. Returns the
+incoming dst value. Refuses to do anything if src or dst is 00000000h (and
+returns 0 in that case).
+
+A(16h) - strncat(dst, src, maxlen)
+Same as "strcat", but clipped to "MaxSrc=(min(0,maxlen)+1)" characters, ie. the
+total length is max "length(dst)+min(0,maxlen)+1". If src is longer or equal to
+"MaxSrc", then only the first "MaxSrc" chars are copied (with the last byte
+being replaced by 00h). If src is shorter, then everything up to the ending 00h
+byte gets copied, but without additional padding (unlike as in "strncpy").
+
+A(17h) - strcmp(str1, str2)
+Compares the strings up to including ending 00h byte. Returns 0 if they are
+identical, or otherwise [str1+N]-[str2+N], where N is the location of the first
+mismatch, the two bytes are sign-expanded to 32bits before doing the
+subtraction. The function rejects str1/str2 values of 00000000h (and returns
+0=both are zero, -1=only str1 is zero, and +1=only str2 is zero).
+
+A(18h) - strncmp(str1, str2, maxlen)
+Same as "strcmp" but stops after comparing "maxlen" characters (and returns 0
+if they did match). If the strings are shorter, then comparision stops at the
+ending 00h byte (exactly as for strcmp).
+
+A(19h) - strcpy(dst, src)
+Copies data from src to dst, up to including the ending 00h byte. Refuses to
+copy anything if src or dst is 00000000h. Returns the incoming dst address (or
+0 if copy was refused).
+
+A(1Ah) - strncpy(dst, src, maxlen)
+Same as "strcpy", but clipped to "maxlen" characters. If src is longer or equal
+to maxlen, then only the first "maxlen" chars are copied (but without appending
+an ending 00h byte to dst). If src is shorter, then the remaining bytes in dst
+are padded with 00h bytes.
+
+A(1Bh) - strlen(src)
+Returns the length of the string up to excluding the ending 00h byte (or 0 when
+src is 00000000h).
+
+A(1Ch) - index(src, char)
+A(1Dh) - rindex(src, char)
+A(1Eh) - strchr(src, char) ;exactly the same as "index"
+A(1Fh) - strrchr(src, char) ;exactly the same as "rindex"
+Scans for the first (index) or last (rindex) occurence of char in the string.
+Returns the memory address of that occurence (or 0 if there's no occurence, or
+if src is 00000000h). Char may be 00h (returns the end address of the string).
+Note that, despite of the function names, the return value is always a memory
+address, NOT an index value relative to src.
+
+A(20h) - strpbrk(src, list)
+Scans for the first occurence of a character that is contained in the list. The
+list contains whatever desired characters, terminated by 00h.
+Returns the address of that occurence, or 0 if there was none. BUG: If there
+was no occurence, it returns 0 only if src[0]=00h, and otherwise returns the
+incoming "src" value (which is the SAME return value as when a occurence did
+occur on 1st character).
+
+A(21h) - strspn(src, list)
+A(22h) - strcspn(src, list)
+Scans for the first occurence of a character that is (strspn), or that isn't
+(strcspn) contained in the list. The list contains whatever desired characters,
+terminated by 00h.
+Returns the index (relative to src) of that occurence. If there was no
+occurence, then it returns the length of src. That silly return values do not
+actually indicate if an occurence has been found or not (unless one checks for
+[src+index]=00h or so).
+***
+"The strcspn() function shall compute the length (in bytes) of the maximum
+initial segment of the string pointed to by s1 which consists entirely of bytes
+not from the string pointed to by s2."
+"The strspn() function shall compute the length (in bytes) of the maximum
+initial segment of the string pointed to by s1 which consists entirely of bytes
+from the string pointed to by s2."
+***
+Hmmmm, that'd be vice-versa?
+
+A(23h) - strtok(src, list) ;first call
+A(23h) - strtok(0, list) ;further call(s)
+Used to split a string into fragments, list contains a list of characters that
+are to be treated as separators, terminated by 00h.
+The first call copies the incoming string to a buffer in the BIOS variables
+area (the buffer size is 100h bytes, so the string should be max 255 bytes
+long, plus the ending 00h byte, otherwise the function destroys other BIOS
+variables), it does then search the first fragment, starting at the begin of
+the buffer. Further calls (with src=00000000h) are searching further fragments,
+starting at the buffer address from the previous call. The internal buffer is
+used only for strtok, so its contents (and the returned string fragments)
+remain intact until a new first call to strtok takes place.
+The separate fragments are processed by searching the first separator, starting
+at the current buffer address, the separator is then replaced by a 00h byte,
+and the old buffer address is returned to the caller. Moreover, the function
+tries to skip all continously following separators, until reaching a
+non-separator, and does memorize that address for the next call (due to that
+skipping further calls won't return empty fragments, the first call may do so
+though). That skipping seems to be bugged, if list contains two or more
+different characters, then additional separators aren't skipped.
+ ",,TEXT,,,END" with list="," returns "", "TEXT", "END"
+ ",,TEXT,,,END" with list=",." returns "", "", "TEXT", "", "", "END"
+Once when there are no more fragments, then 00000000h is returned.
+
+A(24h) - strstr(str, substr) - buggy
+Scans for the first occurence of substr in the string. Returns the memory
+address of that occurence (or 0 if it was unable to find an occurence).
+BUG: After rejecting incomplete matches, the function doesn't fallback to the
+old str address plus 1, but does rather continue at the current str address.
+Eg. it doesn't find substr="aab" in str="aaab" (in that example, it does merely
+realize that "aab"<>"aaa" and then that "aab"<>"b").
+
+BIOS Number/String/Character Conversion
+---------------------------------------
+
+A(0Eh) - abs(val)
+A(0Fh) - labs(val) ;exactly same as "abs"
+Returns the absolute value (if val<0 then R2=-val, else R2=val).
+
+A(0Ah) - todigit(char)
+Takes the incoming character, ANDed with FFh, and returns 0..9 for characters
+"0..9" and 10..35 for "A..Z" or "a..z", or 0098967Fh (9,999,999 decimal) for
+any other 7bit characters, or garbage for characters 80h..FFh.
+
+A(25h) - toupper(char)
+A(26h) - tolower(char)
+Returns the incoming character, ANDed with FFh, with letters "A..Z" converted
+to uppercase/lowercase format accordingly. Works only for char 00h..7Fh (some
+characters in range 80h..FFh are left unchanged, others are randomly "adjusted"
+by adding/subtracting 20h, and by sign-expanding the result to 32bits).
+
+A(0Dh) - strtol(src, src_end, base)
+Converts a string to a number. The function skips any leading "blank"
+characters (that are, 09h..0Dh, and 20h) (ie. TAB, CR, LF, SPC, and some
+others) (some characters in range 80h..FFh are accidently treated as "blank",
+too).
+The incoming base value should be in range 2..11, although the function does
+also accept the buggy values in range of 12..36 (for values other than 2..36 it
+defaults to decimal/base10). The used numeric digits are "0..9" and "A..Z" (or
+less when base is smaller than 36).
+The string may have a negative sign prefix "-" (negates the result) (a "+" is
+NOT recognized; and will be treated as the end of the string). Additionally,
+the string may contain prefixes "0b" (binary/base2), "0x" (hex/base16), or "o"
+(octal/base8) (only "o", not "0o"), allowing to override the incoming "base"
+value.
+BUG: Incoming base values greater than 11 don't work due to the prefix feature
+(eg. base=16 with string "0b11" will be treated as 11 binary, and base=36 with
+string "o55" will be treated as 55 octal) (the only workaround would be to
+add/remove leading "0" characters, ie. "b11" or "00b11" or "0o55" would work
+okay).
+Finally, the function initializes result=0, and does then process the digits as
+"result=result*base+digit" (without any overflow checks) unless/until it
+reaches an unknown digit (or when digit>=base) (ie. the string may end with
+00h, or with any other unexpected characters).
+The function accepts both uppercase and lowercase characters (both as prefixes,
+and as numeric digits). The function returns R2=result, and
+[src_end]=end_address (ie. usually the address of the ending 00h byte; or of
+any other unexpected end-byte). If src points to 00000000h, then the function
+returns r2=0, and leaves [src_end] unchanged.
+
+A(0Ch) - strtoul(src, src_end, base)
+Same as "strtol" except that it doesn't recognize the "-" sign prefix (ie.
+works only for unsigned numbers).
+
+A(10h) - atoi(src)
+A(11h) - atol(src) ;exactly same as "atoi" (but slightly slower)
+Same as "strtol", except that it doesn't return the string end address in
+[src_end], and except that it defaults to base=10, but still supports prefixes,
+allowing to use base2,8,16. CAUTION: For some super bizarre reason, this
+function treats "0" (a leading ZERO digit) as OCTAL prefix (unlike strtol,
+which uses the "o" letter as octal prefix) (the "0x" and "0b" prefixes are
+working as usually).
+
+A(12h) - atob(src, num_dst)
+Calls "strtol(str,src_end,10)", and does then exchange the two return values
+(ie. sets R2=[src_end], and [num_dst]=value_32bit).
+
+A(0Bh) - atof(src) ;USES (ABSENT) COP1 FPU !!!
+A(32h) - strtod(src, src_end) ;USES (ABSENT) COP1 FPU !!!
+These functions are intended to convert strings to floating point numbers,
+however, the functions are accidently compiled for MIPS processors with COP1
+floating point unit (which is not installed in the PSX, nor does the BIOS
+support a COP1 software emulation), so calling these functions will produce a
+coprocessor exception, causing the PSX to lockup via A(40h)
+SystemErrorUnresolvedException.
+
+Note
+On other systems (eg. 8bit computers), "abs/atoi" (integer) and "labs/atol"
+(long) may act differently. However, on the Playstation, both use signed 32bit
+values.
+
+BIOS Misc Functions
+-------------------
+
+A(2Fh) - rand()
+Advances the random generator as "x=x*41C64E6Dh+3039h" (aka plus 12345
+decimal), and returns a 15bit random value "R2=(x/10000h) AND 7FFFh".
+
+A(30h) - srand(seed)
+Changes the current 32bit value of the random generator.
+
+A(B4h) - GetSystemInfo(index) ;not supported by old CEX-1000 version
+Returns a word, halfword, or string, depending on the selected index value:
+ 00h Get Kernel BCD Date (eg. 19951204h) (YYYYMMDDh)
+ 01h Get Kernel Flags or so (usually/always 000000003h)
+ 02h Get Kernel Version String (eg. "CEX-3000/1001/1002 by K.S.",0)
+ 03h Get whatever halfword (usually 0) ;PS2: returns cop0r15
+ 04h Get whatever halfword (usually 0)
+ 05h Get RAM Size in kilobytes (usually 2048) ;=[00000060h] SHL 10
+ 06h..0Eh Get whatever halfwords (usually 0,400h,0,200h,0,0,1,1,1)
+ 0Fh N/A (returns zero) ;PS2: returns 0000h (effectively = same as zero)
+ 10h..FFFFFFFFh Not used (returns zero)
+Note: The Date/Version are referring to the Kernel (in the first half of the
+BIOS). The Intro and Bootmenu (in the second half of the BIOS) may have a
+different version, there's no function to retrieve info on that portion,
+however, a version string for it can be usually found at BFC7FF32h (eg. "System
+ROM Version 4.5 05/25/00 E",0) (in many bios versions, the last letter of that
+string indicates the region, but not in all versions) (the old SCPH1000 does
+not include that version string at all).
+
+B(56h) GetC0Table()
+B(57h) GetB0Table()
+Retrieves the address of the jump lists for B(NNh) and C(NNh) functions,
+allowing to patch entries in that lists (however, the BIOS does often jump
+directly to the function addresses, rather than indirectly via the list, so
+patching may have little effect in such cases). Note: There's no function to
+retrieve the address of the A(NNh) jump list, however, that list is
+usually/always at 00000200h.
+
+A(31h) - qsort(base, nel, width, callback)
+Sorts an array, using a super-slow implementation of the "quick sort"
+algorithm. base is the address of the array, nel is the number of elements in
+the array, width is the size in bytes of each element, callback is a function
+that receives pointers to two elements which need to be compared; callback
+should return return zero if the elements are identical, or a positive/negative
+number to indicate which element is bigger.
+The qsort function rearranges the contents of the array, ie. depending on the
+callback result, it may swap the contents of the two elements, for some bizarre
+reason it doesn't swap them directly, but rather stores one of the elements
+temporarily on the heap (that means, qsort works only if the heap was
+initialized with InitHeap, and only if "width" bytes are free). There's no
+return value.
+
+A(35h) - lsearch(key, base, nel, width, callback)
+A(36h) - bsearch(key, base, nel, width, callback)
+Searches an element in an array (key is the pointer to the searched element,
+the other parameters are same as for "qsort"). "lsearch" performs a slow linear
+search in an unsorted array, by simply comparing one array element after each
+other. "bsearch" assumes that the array contains sorted elements (eg. via
+qsort), which is allowing to skip some elements, and to jump back and forth in
+the array, until it has found the desired element (or the location where it'd
+be, if it'd be in the array). Both functions return the address of the element
+(or 0 if it wasn't found).
+
+C(19h) - ioabort(txt1,txt2)
+Displays the two strings on the TTY (in some cases the BIOS does accidently
+pass garbage instead of the 2nd string though). And does then execute
+ioabort_raw(1), see there for more details.
+
+A(B2h) - ioabort_raw(param) ;not supported by old CEX-1000 version
+Executes "RestoreState(ioabortbuffer,param)". Internally used to recover from
+failed I/O operations, param should be nonzero to notify the SaveState caller
+that the abort has occurred.
+
+A(13h) - SaveState(buf)
+Stores some (not all) CPU registers in the specified buffer (30h bytes):
+ 00h 4 r31 (ra) (aka caller's pc)
+ 04h 4 r29 (sp)
+ 08h 4 r30 (fp)
+ 0Ch 4x8 r16..r23
+ 2Ch 4 r28 (gp)
+That type of buffer can be used with "ioabort", "RestoreState", and also
+"SetCustomExitFromException(addr)".
+The "SaveState" function (initially) returns 0, however, it may return again -
+to the same return address - with another return value (which should be usually
+non-zero, to indicate that the state has been restored (eg. ioabort passes 1 as
+return value).
+
+A(14h) - RestoreState(buf, param)
+Restores the R16-R23,GP,SP,FP,RA registers from a previously recorded SaveState
+buffer, and "returns" to that new RA address (rather than to the caller of the
+RestoreState function), the "param" value is passed as "return value" to the
+code at RA, ie. usually to the caller of the original SaveState call) (since
+SaveState returns 0, "param" should be usually 1, or another non-zero value to
+inidicate that RestoreState has occurred). See SaveState for further details.
+
+A(53h) - set_ioabort_handler(src) ;PS2 only ;PSX: SystemError
+Normally the ioabort handler is changed only internally during booting, with
+this new function, games can install their own ioabort handler. src is pointer
+to a 30h-byte "savestate" structure, which will be copied to the actual ioabort
+structure.
+
+A(06h) or B(38h) - exit(exitcode)
+Terminates the program and returns control to the BIOS; which does then lockup
+itself via A(3Ah) SystemErrorExit.
+
+A(A0h) - WarmBoot()
+Performs a warmboot (resets the kernel and reboots from CDROM). Unlike the
+normal coldboot procedure, it doesn't display the "<S>" and "PS" intro screens
+(and doesn't verify the "PS" logo in the ISO System Area), and, doesn't enter
+the bootmenu (even if the disk drive is empty, or if it contains an Audio
+disk). And, it doesn't reload the SYSTEM.CNF file, so the function works only
+if the same disk is still inserted (or another disk with identical SYSTEM.CNF,
+such like Disk 2 of the same game).
+
+A(B5h..BFh) B(11h,24h..29h,2Ch..31h,5Eh..FFh) C(1Eh..7Fh) - N/A - Jump 0
+These functions jump to address 00000000h. For whatever reason, that address
+does usually contain a copy of the exception handler (ie. same as at address
+80000080h). However, since there's no return address stored in EPC register,
+the functions will likely crash when returning from the exception handler.
+
+A(57h..5Ah,73h..77h,79h..7Bh,7Dh,7Fh..80h,82h..8Fh,B0h..B1h,B3h), and
+C(0Eh..11h,14h) - N/A - Returns 0
+No function. Simply returns with r2=00000000h.
+Reportedly, A(85h) is CdStop, but that seems to be nonsense?
+
+SYS(00h) - NoFunction()
+No function. Simply returns without changing any registers or memory locations
+(except that, of course, the exception handler destroys k0).
+
+SYS(04h..FFFFFFFFh) - calls DeliverEvent(F0000010h,4000h)
+These are syscalls with invalid function number in R4. For whatever reason that
+is handled by issuing DeliverEvent(F0000010h,4000h). Thereafter, the syscall
+returns to the main program (ie. it doesn't cause a SystemError).
+
+A(3Ah) - SystemErrorExit(exitcode)
+A(40h) - SystemErrorUnresolvedException()
+A(A1h) - SystemErrorBootOrDiskFailure(type,errorcode) ;type "B"=Boot,"D"=Disk
+These are used "SystemError" functions. The functions are repeatedly jumping to
+themselves, causing the system to hang. Possibly useful for debugging software
+which may hook that functions.
+
+A(4Fh,50h,52h,53h,9Ah,9Bh) B(1Ah..1Fh,21h..23h,2Ah,2Bh,52h,5Ah) C(0Bh) - N/A
+These are additional "SystemError" functions, but they are never used. The
+functions are repeatedly jumping to themselves, causing the system to hang.
+Note: A(52h) is reportedly "GetSysSp()", but that seems to be nonsense?
+
+BRK(1C00h) - Division by zero (commonly checked/invoked by software)
+BRK(1800h) - Division overflow (-80000000h/-1, sometimes checked by software)
+The CPU does not generate any exceptions upon divide overflows, because of
+that, the Kernel code and many games are commonly checking if the divider is
+zero (by software), and, if so, execute a BRK 1C00h opcode. The default BIOS
+exception handler doesn't handle BRK exceptions, and does simply redirect them
+to SystemErrorUnresolvedException().
+
+BIOS Internal Boot Functions
+----------------------------
+
+A(45h) - init_a0_b0_c0_vectors
+Copies the three default four-opcode handlers for the A(NNh),B(NNh),C(NNh)
+functions to A00000A0h..A00000CFh.
+
+C(07h) - InstallExceptionHandlers() ;destroys/uses k0/k1
+Copies the default four-opcode exception handler to the exception vector at
+80000080h..8000008Fh, and, for whatever reason, also copies the same opcodes to
+80000000h..8000000Fh.
+
+C(08h) - SysInitMemory(addr,size)
+Initializes the address (A000E000h) and size (2000h) of the allocate-able
+Kernel Memory region, and, seems to deallocate any memory handles which may
+have been allocated via B(00h).
+
+C(09h) - SysInitKernelVariables()
+Zerofills all Kernel variables; which are usually at [00007460h..0000891Fh].
+Note: During the boot process, the BIOS accidently overwrites the first opcode
+of this function (by the last word of the A0h table), so, thereafter, this
+function won't work anymore (nor would it be of any use).
+
+C(12h) - InstallDevices(ttyflag)
+Initializes the size and address of the File and Device Control Blocks (FCBs
+and DCBs). Adds the TTY device by calling "KernelRedirect(ttyflag)", and the
+CDROM and Memory Card devices by calling "AddCDROMDevice()" and
+"AddMemCardDevice()".
+
+C(1Ch) - AdjustA0Table()
+Copies the B(32h..3Bh) and B(3Ch..3Fh) function addresses to A(00h..09h) and
+A(3Bh..3Eh). Apparently Sony's compiler/linker can't insert the addresses in
+the A0h table directly at compilation time, so this function is used to insert
+them during execution of the boot code.
+
+BIOS More Internal Functions
+----------------------------
+
+Below are mainly internally used device related subfunctions.
+
+Internal Device Stuff
+ A(5Bh) dev_tty_init() ;PS2: SystemError
+ A(5Ch) dev_tty_open(fcb,and unused:"path\name",accessmode) ;PS2: SystemError
+ A(5Dh) dev_tty_in_out(fcb,cmd) ;PS2: SystemError
+ A(5Eh) dev_tty_ioctl(fcb,cmd,arg) ;PS2: SystemError
+ A(5Fh) dev_cd_open(fcb,"path\name",accessmode)
+ A(60h) dev_cd_read(fcb,dst,len)
+ A(61h) dev_cd_close(fcb)
+ A(62h) dev_cd_firstfile(fcb,"path\name",direntry)
+ A(63h) dev_cd_nextfile(fcb,direntry)
+ A(64h) dev_cd_chdir(fcb,"path")
+ A(65h) dev_card_open(fcb,"path\name",accessmode)
+ A(66h) dev_card_read(fcb,dst,len)
+ A(67h) dev_card_write(fcb,src,len)
+ A(68h) dev_card_close(fcb)
+ A(69h) dev_card_firstfile(fcb,"path\name",direntry)
+ A(6Ah) dev_card_nextfile(fcb,direntry)
+ A(6Bh) dev_card_erase(fcb,"path\name")
+ A(6Ch) dev_card_undelete(fcb,"path\name")
+ A(6Dh) dev_card_format(fcb)
+ A(6Eh) dev_card_rename(fcb1,"path\name1",fcb2,"path\name2")
+ A(6Fh) ? ;card ;[r4+18h]=00000000h ;card_clear_error(fcb) or so
+ A(96h) AddCDROMDevice()
+ A(97h) AddMemCardDevice()
+ A(98h) AddDuartTtyDevice() ;PS2: SystemError
+ A(99h) AddDummyTtyDevice()
+ B(47h) AddDevice(device_info) ;subfunction for AddXxxDevice functions
+ B(48h) RemoveDevice(device_name_lowercase)
+ B(5Bh) ChangeClearPad(int) ;pad AND card (ie. used also for Card)
+ C(15h) tty_cdevinput(circ,char)
+ C(16h) tty_cdevscan()
+ C(17h) tty_circgetc(circ) ;uses r5 as garbage txt for ioabort
+ C(18h) tty_circputc(char,circ)
+
+Device Names
+Device Names are case-sensitive (usually lowercase, eg. "bu" for memory cards).
+In filenames, the device name may be followed by a hexadecimal 32bit
+non-case-sensitive port number (eg. "bu00:" for selecting the first memory card
+slot). Accordingly, the device name should not end with a hexdigit (eg. "usb:"
+would be treated as device "us" with port number 0Bh).
+Standard device names are "cdrom:", "bu00:", "bu10:", "tty00:". Other,
+nonstandard devices are:
+ Castlevania is trying to access an unknown device named "sim:".
+ Caetla (a firmware replacement for Cheat Devices) supports "pcdrv:" device.
+
+BIOS PC File Server
+-------------------
+
+DTL-H2000
+Below BRK's are internally used in DTL-H2000 BIOS for two devices: "mwin:"
+(Message Window) and "sim:" (CDROM Sim).
+
+Caetla Blurb
+Caetla (a firmware replacement for Cheat Devices) supports "pcdrv:" device, the
+SN systems (=what?) device extension to access files on the drive of the pc.
+This fileserver can be accessed by using the kernel functions, with the
+"pcdrv:" device name prefix to the filenames or using the SN system calls.
+The following SN system calls for the fileserver are provided. Accessed by
+setting the registers and using the break command with the specified field.
+The break functions have argument(s) in A1,A2,A3 (ie. unlike normal BIOS
+functions not in A0,A1,A2), and TWO return values (in V0, and V1).
+
+Detection
+WCW Mayhem (MagDemo28) examines the exception vector opcodes to determine
+whether to initialize debug stuff, the opcodes are usually:
+ 80000080h = LUI+ADDIU+JMP+NOP ;normal sony bios
+ 80000080h = LUI+ORI+JMP+NOP ;whatever debug bios (caetla or so?)
+Namely, WCW Mayhem is doing "IF [86h]=375Ah=ORI then BRK(101h)". To avoid
+crashing on that BRK, normal BIOSes must not use ORI in that place.
+
+BRK(101h) - PCInit() - Inits the fileserver
+No parameters.
+
+BRK(102h) - PCCreat(filename, fileattributes) - Creates a new file on PC
+ out: V0 0 = success, -1 = failure
+ V1 file handle or error code if V0 is negative
+Attributes Bits (standard MSDOS-style):
+ bit0 Read only file (R)
+ bit1 Hidden file (H)
+ bit2 System file (S)
+ bit3 Not used (zero)
+ bit4 Directory (D)
+ bit5 Archive file (A)
+ bit6-31 Not used (zero)
+
+BRK(103h) - PCOpen(filename, accessmode) - Opens a file on the PC
+ out: V0 0 = success, -1 = failure
+ V1 file handle or error code if V0 is negative
+
+BRK(104h) - PCClose(filehandle) - Closes a file on the PC
+ out: V0 0 = success, -1 = failure
+ V1 0 = success, error code if V0 is negative
+
+BRK(105h) - PCRead(filehandle, length, memory_destination_address)
+ out: V0 0 = success, -1 = failure
+ V1 number of read bytes or error code if V0 is negative.
+Note: PCRead does not stop at EOF, so if you set more bytes to read than the
+filelength, the fileserver will pad with zero bytes. If you are not sure of the
+filelength obtain the filelength by PClSeek (A2=0, A3=2, V1 will return the
+length of the file, don't forget to reset the file pointer to the start before
+calling PCread!)
+
+BRK(106h) - PCWrite(filehandle, length, memory_source_address)
+ out: V0 0 = success, -1 = failure
+ V1 number of written bytes or error code if V0 is negative.
+
+BRK(107h) - PClSeek(filehandle, file_offset, seekmode) - Change Filepos
+seekmode may be from 0=Begin of file, 1=Current fpos, or 2=End of file.
+ out: V0 0 = success, -1 = failure
+ V1 file pointer
+
+BIOS TTY Console (std_io)
+-------------------------
+
+A(3Fh) - Printf(txt,param1,param2,etc.) - Print string to console
+ in: A0 Pointer to 0 terminated string
+ A1,A2,A3,[SP+10h..] Argument(s)
+Prints the specified string to the TTY console. Printf does internally use
+"std_out_putchar" to output the separate characters (and expands char 09h and
+0Ah accordingly).
+The string can contain C-style escape codes (prefixed by "%" each):
+ c display ASCII character
+ s display ASCII string
+ i,d,D display signed Decimal number (d/i=default32bit, D=force32bit)
+ u,U display unsigned Decimal number (u=default32bit, U=force32bit)
+ o,O display unsigned Octal number (o=default32bit, O=force32bit)
+ p,x,X display unsigned Hex number (p=lower/force32bit, x=lower, X=upper)
+ n write 32bit/16bit string length to [parameter] (default32bit)
+Additionally, following prefixes (inserted between "%" and escape code):
+ + or SPC show leading plus or space character in positive signed numbers
+ NNN fixed width (for padding or so) (first digit must be 1..9) (not 0)
+ .NNN fixed width (for clipping or so)
+ * variable width (using one of the parameters) (negative=ending_spc)
+ .* variable width
+ - force ending space padding (in case of width being specified)
+ # show leading "0x" or "0X" (hex), or ensure 1 leading zero (octal)
+ 0 show leading zero's
+ L unknown/no effect?
+ h,l force 16bit (h=halfword), or 32bit (l=long/word)
+The force32bit codes (D,U,O,p,l) are kinda useless since the PSX defaults to
+32bit parameters anyways. The force16bit code (h) may be useful as "%hn"
+(writeback 16bit value), otherwise it's rather useless, unless signed 16bit
+parameters have garbage in upper 16bit, for unsigned 16bit parameters it
+doesn't work at all (accidently sign-expands 16bit to 32bit, and then displays
+that signed 32bit value as giant unsigned value). Printf supports only octal,
+decimal, and hex (but not binary).
+
+A(3Eh) or B(3Fh) std_out_puts(src) - Write string to TTY
+ in: R4=address of string (terminated by 00h)
+Like "printf", but doesn't resolve any "%" operands. Empty strings are handled
+in a special way: If R4 points to a 00h character then nothing is output (as
+one would expect it), but, if R4 is 00000000h then "<NULL>" is output (only
+that six letters; without appending any CR or LF).
+
+A(3Dh) or B(3Eh) std_in_gets(dst) - Read string from TTY (keyboard input)
+ in: r4=dst (pointer to a 128-byte buffer) - out: r2=dst (same is incoming r4)
+Internally uses "std_in_getchar" to receive the separate characters (which are
+thus masked by 7Fh). The received characters are stored in the buffer, and are
+additionally sent back as echo to the TTY via std_out_putc.
+The following characters are handled in a special way: 09h (TAB) is replaced by
+a single SPC. 08h or 7FH (BS or DEL) are removing the last character from the
+buffer (unless it is empty) and send 08h,20h,08h (BS,SPC,BS) to the TTY. 0Dh or
+0Ah (CR or LF) do terminate the input (append 00h to the buffer, send 0Ah to
+the TTY, which is expanded to 0Dh,0Ah by the std_out_putc function, and do then
+return from the std_in_gets function).
+The sequence 16h,NNh forces NNh to be stored in the buffer (even if NNh is a
+special character like 00h..1Fh or 7Fh). If the buffer is full (circa max 125
+chars, plus one extra byte for the ending 00h), or if an unknown control code
+in range of 00h..1Fh is received without the 16h prefix, then 07h (BELL) is
+sent to the TTY.
+
+A(3Bh) or B(3Ch) std_in_getchar() - Read character from TTY
+Reads one character from the TTY console, by internally redirecting to
+"FileRead(0,tempbuf,1)". The returned character is ANDed by 7Fh (so, to read a
+fully intact 8bit character, "FileRead(0,tempbuf,1)" must be used instead of
+this function).
+
+A(3Ch) or B(3Dh) std_out_putchar(char) - Write character to TTY
+Writes the character to the TTY console, by internally redirecting to
+"FileWrite(1,tempbuf,1)". Char 09h (TAB) is expanded to one or more SPC
+characters, until reaching the next tabulation boundary (every 8 characters).
+Char 0Ah (LF) is expanded to 0Dh,0Ah (CR,LF). Other special characters (which
+should be handled at the remote terminal side) are 08h (BS, backspace, move
+cursor one position to the left), and 07h (BELL, produce a short beep sound).
+
+C(13h) FlushStdInOutPut()
+Closes and re-opens the std_in (fd=0) and std_out (fd=1) file handles.
+
+C(1Bh) KernelRedirect(ttyflag) ;PS2: ttyflag=1 causes SystemError
+Removes, re-mounts, and flushes the TTY device, the parameter selects whether
+to mount the real DUART-TTY device (r4=1), or a Dummy-TTY device (r4=0), the
+latter one sends any std_out to nowhere. Values other than r4=0 or r4=1 do
+remove the device, but do not re-mount it (which might result in problems).
+Caution: Trying to use r4=1 on a PSX that does not has the DUART hardware
+installed causes the BIOS to hang (so one should first detect the DUART
+hardware, eg. by writing two different bytes to Port 1F802020h.1st/2nd access,
+and the read and verify that two bytes).
+
+Activating std_io
+The std_io functions can be enabled via C(1Bh) KernelRedirect(ttyflag), the
+BIOS is unable to detect the presence of the TTY hardware, by default the BIOS
+bootcode disables std_io by setting the initial KernelRedirect value at
+[A000B9B0h] to zero, this is hardcoded shortly after the POST(E) output:
+ call output_post_r4 ;\output POST(E)
+ +mov r4,0Eh ;/
+ mov r1,0A0010000h ;\set [0A000B9B0h]=0 ;TTY=dummy/off
+ call reset_cont_d_3 ; and call reset_cont_d_3
+ +mov [r1-4650h],0 ;/
+assuming that R28=A0010FF0h, the last 3 opcodes of above code can be replaced
+by:
+ mov r1,1h ;\set [0A000B9B0h]=1 ;TTY=duart/on
+ call reset_cont_d_3 ; and call reset_cont_d_3
+ +mov [r28-4650h-0ff0h],r1 ;/
+with that patch, the BIOS bootcode (and many games) are sending debug messages
+to the debug terminal, via expansion port, see:
+--> EXP2 Dual Serial Port (for TTY Debug Terminal)
+Note: The nocash BIOS automatically detects the DUART hardware, and activates
+TTY if it is present.
+
+B(49h) PrintInstalledDevices()
+Uses printf to display the long and short names from the DCB of the currently
+installed devices. Doesn't do anything else. There's no return value.
+
+Note
+Several BIOS functions are internally using printf to output status
+information, timeout, and error messages, etc. So, trying to close the TTY file
+handles (fd=0 and fd=1) would cause such functions to work unstable.
+
+BIOS Character Sets
+-------------------
+
+B(51h) Krom2RawAdd(shiftjis_code)
+ In: r4 = 16bit Shift-JIS character code
+ Out: r2 = address in BIOS ROM of the desired character (or -1 = error)
+r4 should be 8140h..84BEh (charset 2), or 889Fh..9872h (charset 3).
+
+B(53h) Krom2Offset(shiftjis_code)
+ In: r4 = 16bit Shift-JIS character code
+ Out: r2 = offset within charset (without charset base address)
+This is a subfunction for B(51h) Krom2RawAdd(shiftjis_code).
+
+Character Sets in ROM (112Kbytes)
+The character sets are located at BFC64000h and up, intermixed with some other
+stuff:
+ BFC64000h Charset 1 (16x15 pix, letters with accent marks) (NOT in JAPAN)
+ BFC65CB6h Garbage (four-and-a-half reverb tables, ioports, printf strings)
+ BFC66000h Charset 2 (16x15 pix, various alphabets, english, greek, etc.)
+ BFC69D68h Charset 3 (16x15 pix, japanese or chinese symbols or so)
+ BFC7F8DEh Charset 4 (8x15 pix, mainly ASCII letters)
+ BFC7FE6Fh Charset 5 (8x15 pix, additional punctuation marks) (NOT in PS2)
+ BFC7FF32h Version (Version and Copyright strings) (NOT in SCPH1000)
+ BFC7FF8Ch Charset 6 (8x15 pix, seven-and-a-half japanese chars) (NOT in PS2)
+ BFC80000h End (End of 512kBYTE BIOS ROM)
+Charset 1 (and Garbage) is NOT included in japanese BIOSes (in the SCPH1000
+version that region contains uncompressed program code, in newer japanese
+BIOSes that regions are zerofilled)
+Charset 1 symbols are as defined in JIS-X-0212 char(2661h..2B77h), and EUC-JP
+char(8FA6E0h..8FABF7h).
+Version (and Copyright) string is NOT included in SCPH1000 version (that BIOS
+includes further japanese 8x15 pix chars in that region).
+For charset 2 and 3 it may be recommended to use the B(51h)
+Krom2RawAdd(shiftjis_code) to obtain the character addresses. There is no BIOS
+function to retrieve charset 1, 4, 5, and 6 addresses.
+
+BIOS Control Blocks
+-------------------
+
+Exception Control Blocks (ExCB) (4 blocks of 8 bytes each)
+ 00h 4 ptr to first element of exception chain
+ 04h 4 not used (zero)
+
+Event Control Blocks (EvCB) (usually 16 blocks of 1Ch bytes each)
+ 00h 4 class (events are triggered when class and spec match)
+ 04h 4 status (0=free,1000h=disabled,2000h=enabled/busy,4000h=enabled/ready)
+ 08h 4 spec (events are triggered when class and spec match)
+ 0Ch 4 mode (1000h=execute function/stay busy, 2000h=no func/mark ready)
+ 10h 4 ptr to function to be executed when ready (or 0=none)
+ 14h 8 not used (uninitialized)
+
+Thread Control Blocks (TCB) (usually 4 blocks of 0C0h bytes each)
+ 00h 4 status (1000h=Free TCB, 4000h=Used TCB)
+ 04h 4 not used (set to 1000h by OpenThread) (not for boot executable?)
+ 08h 80h r0..r31 (entries for r0/zero and r26/k0 are unused)
+ 88h 4 cop0r14/epc (aka r26/k0 and pc when returning from exception)
+ 8Ch 8 hi,lo (the mul/div registers)
+ 94h 4 cop0r12/sr (stored/restored by exception, NOT init by OpenThread)
+ 98h 4 cop0r13/cause (stored when entering exception, NOT restored on exit)
+ 9Ch 24h not used (uninitialized)
+
+Process Control Block (1 block of 4 bytes)
+ 00h 4 ptr to TCB of current thread
+The PSX supports only one process, and thus only one Process Control Block.
+
+File Control Blocks (FCB) (16 blocks of 2Ch bytes each)
+ 00h 4 status (0=Free FCB) (nonzero=accessmode)
+ 04h 4 cdrom: disk_id (checksum across path table of the corresponding disk),
+ memory card: port number (00h=slot1, 10h=slot2)
+ 08h 4 transfer address (for dev_in_out function)
+ 0Ch 4 transfer length (for dev_in_out function)
+ 10h 4 current file position
+ 14h 4 device flags (copy of DCB[04h])
+ 18h 4 error ;used by B(55h) - GetLastFileError(fd)
+ 1Ch 4 Pointer to DCB for the file
+ 20h 4 filesize
+ 24h 4 logical block number (start of file) (for cdrom: at least)
+ 28h 4 file control block number (simply 0..15 for FCB number 0..15)
+
+Device Control Blocks (DCB) (10 blocks of 50h bytes each)
+ 00h 4 ptr to lower-case short name ("cdrom", "bu", "tty") (or 0=Free DCB)
+ 04h 4 device flags (cdrom=14h, bu=14h, tty/dummy=1, tty/duart=3)
+ 08h 4 sector size (cdrom=800h, bu=80h, tty=1)
+ 0Ch 4 ptr to upper-case long name ("CD-ROM", "MEMORY CARD", "CONSOLE")
+ 10h 4 ptr to init() (TTY only)
+ 14h 4 ptr to open(fcb,"path\name",accessmode)
+ 18h 4 ptr to in_out(fcb,cmd) (TTY only)
+ 1Ch 4 ptr to close(fcb)
+ 20h 4 ptr to ioctl(fcb,cmd,arg) (TTY only)
+ 24h 4 ptr to read(fcb,dst,len)
+ 28h 4 ptr to write(fcb,src,len)
+ 2Ch 4 ptr to erase(fcb,"path\name")
+ 30h 4 ptr to undelete(fcb,"path\name")
+ 34h 4 ptr to firstfile(fcb,"path\name",direntry)
+ 38h 4 ptr to nextfile(fcb,direntry)
+ 3Ch 4 ptr to format(fcb)
+ 40h 4 ptr to chdir(fcb,"path") (CDROM only)
+ 44h 4 ptr to rename(fcb1,"path\name1",fcb2,"path\name2")
+ 48h 4 ptr to remove()
+ 4Ch 4 ptr to testdevice(fcb,"path\name")
+
+BIOS Boot State
+---------------
+
+The BIOS/Kernel is doing little hardware initialization, however, most of the
+GPU/GTE/SPU registers contain leftovers from the BIOS/GUI, namely from the
+"PS"-intro. Though there are some special cases:
+ - GUI 1.0j displays "PS"-intro only for japanese discs (but does allow to
+ boot non-japanese discs, but without showing the "PS"-intro; so GPU/SPU
+ leftovers are then from "<S>"-intro, and GTE is left uninitialized).
+ - Some registers may differ when inserting a CDROM while in boot menu.
+ - There may be small differences depending on CDROM loading time.
+ - Expansion ROMs or Kernel Clones may initialize some things differently.
+ - Different Kernel versions may differ (especially on initial CPU registers).
+Values below were recorded in no$psx, some values might differ on real
+hardware.
+
+Games
+Most games are initializing all required hardware registers, but some do rely
+on GUI leftovers:
+ - Saga Frontier requires GPU display enable via GP1(03h)=0
+
+CPU Registers
+ pc = <ExeEntrypoint> r16/s0 = 0a000b870h ;kernel ram
+ r1/at = 000000005h r17/s1 = 0
+ r2/v0 = 000000001h r18/s2 = 0
+ r3/v1 = 000000004h ;can be 1 or 4 r19/s3 = 0
+ r4/a0 = 000000001h ;boot param1=1 r20/s4 = 0
+ r5/a1 = 0 ;boot param2=0 r21/s5 = 0
+ r6/a2 = 0 r22/s6 = 0
+ r7/a3 = 00000002Ah r23/s7 = 0bfc0702ch ;kernel rom
+ r8/t0 = <SystemCnfSp> ;from do_exec r24/t8 = 00000001fh
+ r9/t1 = 0 ;from do_exec r25/t9 = 01f801802h ;I/O addr
+ r10/t2 = 00000002dh r26/k0 = 0bfc0d968h ;kernel rom
+ r11/t3 = <ExeEntrypoint> r27/k1 = 000000f1ch
+ r12/t4 = 000000023h r28/gp = 0
+ r13/t5 = 00000002bh r29/sp = <SystemCnfSp> ;sp
+ r14/t6 = 000000001h r30/fp = <SystemCnfSp> ;same as sp
+ r15/t7 = 01f801800h ;I/O addr r31/ra = <RetadrToKernel>
+ lo = 000000001h hi = 0
+
+COP0 Registers (System)
+ cop0r6/jumpdest = <varies> cop0r3/bpc = 0
+ cop0r8/badvaddr = FFFFFFFFh cop0r5/bda = 0
+ cop0r12/sr = 40000000h cop0r7/dcic = 0
+ cop0r13/cause = 00000020h cop0r9/bdam = 0
+ cop0r14/epc = <RetadrFromIrq> cop0r11/bpcm = 0
+ cop0r15/prid = 00000002h, or 1
+
+COP2 Registers (GTE)
+ cop2r0 = 000000b50h ;\vector0 cop2r32 = 000000ffbh ;\
+ cop2r1 = 000000b50h ;/ cop2r33 = 0ffb7ff44h ; rotation
+ cop2r2 = 0fdabff8dh ;\vector1 cop2r34 = 0f9ca0ebch ; matrix
+ cop2r3 = 0fffffe51h ;/ cop2r35 = 0063700adh ;
+ cop2r4 = 0fdab000ah ;\vector2 cop2r36 = 000000eb7h ;/
+ cop2r5 = 0fffffdd4h ;/ cop2r37 = 0 ;\translation
+ cop2r6 = 0200808ffh ;-rgbc cop2r38 = 0fffffeach ; vector
+ cop2r7 = 000000509h ;-otz cop2r39 = 000001700h ;/
+ cop2r8 = 0000000a4h ;-ir0 cop2r40 = 0 ;\
+ cop2r9 = 00000104ah ;\ cop2r41 = 000000fa0h ; light source
+ cop2r10 = 000000082h ; ir1-3 cop2r42 = 00000f060h ; matrix
+ cop2r11 = 000000082h ;/ cop2r43 = 00000f060h ;
+ cop2r12 = 00041012dh ;\ cop2r44 = 0 ;/
+ cop2r13 = 00063012dh ; screen cop2r45 = 000000640h ;\background
+ cop2r14 = 000690146h ; xy fifo cop2r46 = 000000640h ; color
+ cop2r15 = 000690146h ;/ cop2r47 = 000000640h ;/
+ cop2r16 = 000001441h ;\ cop2r48 = 00bb80fa0h ;\
+ cop2r17 = 000001441h ; screen cop2r49 = 00fa00fa0h ; light color
+ cop2r18 = 000001486h ; z fifo cop2r50 = 00fa00bb8h ; matrix source
+ cop2r19 = 000001419h ;/ cop2r51 = 00bb80fa0h ;
+ cop2r20 = 0200808ffh ;\color cop2r52 = 000000fa0h ;/
+ cop2r21 = 0200808ffh ; rgb fifo cop2r53 = 0 ;\
+ cop2r22 = 0200808ffh ;/ cop2r54 = 0 ; far color
+ cop2r23 = 0 ;-reserved cop2r55 = 0 ;/
+ cop2r24 = 0fffffcaeh ;-mac0 cop2r56 = 001400000h ;\screen offset
+ cop2r25 = 00000104ah ;\ cop2r57 = 000f00000h ;/
+ cop2r26 = 000000082h ; mac1-3 cop2r58 = 000000400h ;-h
+ cop2r27 = 000000082h ;/ cop2r59 = 0fffff9e9h ;-dqa
+ cop2r28 = 00000043fh ;-irgb cop2r60 = 001400000h ;-dqb
+ cop2r29 = 00000043fh ;-orgb cop2r61 = 000000155h ;\average z scale
+ cop2r30 = 0 ;-lzcs cop2r62 = 000000100h ;/
+ cop2r31 = 000000020h ;-lzcr cop2r63 = 000600000h ;-flag
+
+GPU/MDEC Registers
+ GP1(03h)=000000h display_disable (0=on)
+ GP1(04h)=000000h dma_direction
+ GP1(05h)=000800h display_address
+ GP1(06h)=c7e27eh display_x_range
+ GP1(07h)=04682bh display_y_range
+ GP1(08h)=000027h+bit3 display_mode (bit3=pal)
+ GP1(09h)=000000h tex_disable
+ GP0(E1h)=00300Dh tex_page
+ GP0(E2h)=000000h=GP1(10h:2) tex_window
+ GP0(E3h)=000800h=GP1(10h:3) draw_x1y1
+ GP0(E4h)=077e7fh=GP1(10h:4) draw_x2y2
+ GP0(E5h)=001000h=GP1(10h:5) draw_offset
+ GP0(E6h)=000000h mask_setting
+ GP1(10h:7)=000002h (if any) gpu_version
+ GP1(10h:8)=000000h (if any) unknown
+ [1f801814h]=144e200dh+bit31+bit20 gpu_stat (bit31=even/odd, bit20=pal)
+ [1f801824h]=80040000h mdec_stat
+VRAM isn't cleared when starting the EXE (it does usually contain the
+640x480pix bootscreen with the PS logo, and some related textures).
+MDEC quant/scale tables are uninitialized (unknown if /RESET sets them to some
+default values, or zeroes, or random).
+
+CDROM Registers
+ stat=02h, mode=20h, file=00h, channel=00h
+ [1f801800h.read]=39h ;index
+ [1f801803h.read.0]=FFh ;irq.enable
+ [1f801803h.read.1]=E0h ;irq.flag
+
+Misc Registers
+ exp1_base [1f801000h]=1f000000h ;\
+ exp2_base [1f801004h]=1f802000h ;
+ exp1_siz [1f801008h]=0013243fh ;
+ exp3_siz [1f80100ch]=00003022h ; memory control 1
+ bios_siz [1f801010h]=0013243fh ;
+ spu_siz [1f801014h]=200931e1h ;
+ cdrom_siz [1f801018h]=00020943h ;
+ exp2_siz [1f80101ch]=00070777h ;
+ com_delay [1f801020h]=0000132ch ;/
+ ram_siz [1f801060h]=00000b80h+bit3 ;-memory control 2 (bit3=newtype)
+ cache_cnt [fffe0130h]=0001e988h ;-cache control
+ post [1f802041h]=09h ;-post (write-only, if any)
+ joy_data [1f801040h]=00000000h ;\
+ joy_stat [1f801044h]=00000805h ;
+ joy_mode [1f801048h]=0000h ; joypad
+ joy_ctrl [1f80104ah]=0000h ;
+ joy_baud [1f80104eh]=0000h ;/
+ sio_data [1f801050h]=00000000h ;\
+ sio_stat [1f801054h]=00000805h ;
+ sio_mode [1f801058h]=0000h ; sio
+ sio_ctrl [1f80105ah]=0000h ;
+ sio_misc [1f80105ch]=0000h ;
+ sio_baud [1f80105eh]=0000h ;/
+ irq_stat [1f801070h]=00000001h ;\interrupt control
+ irq_mask [1f801074h]=0000000ch ;/
+
+DMA Registers (addr,len,cnt)
+ [1f801080h]=<random> ,<random> ,00000000h ;dma0 mdec.in
+ [1f801090h]=<random> ,<random> ,00000000h ;dma1 mdec.out
+ [1f8010a0h]=00ffffffh,00000000h,00000401h ;dma2 gpu
+ [1f8010b0h]=<ExeLast>,00010200h,00000000h ;dma3 cdrom
+ [1f8010c0h]=<random> ,<random> ,00000000h ;dma4 spu
+ [1f8010d0h]=<random> ,<random> ,00000000h ;dma5 pio
+ [1f8010e0h]=00129834h,00000400h,00000002h ;dma6 otc
+ [1f8010f0h]=00009099h ;dma_cnt
+ [1f8010f4h]=848c0000h ;dma_irq
+ [1f8010f8h]=0BFAC688h ;dma_unk1
+ [1f8010fch]=00000000h ;dma_unk2
+DMA3 has ExeLast=(ExeEnd-800h) and 00ffffffh.
+
+Timer Registers (val,mode,dest)
+ [1f801100h,04h,08h]=<T+009Ch>,1c00h,0000h ;timer0
+ [1f801110h,04h,08h]=<T+004Eh>,1c00h,0000h ;timer1
+ [1f801120h,04h,08h]=<T+0000h>,1c00h,0000h ;timer2
+The timers are running in SysClk mode, and they are started almost
+simultaneously, and do thus contain almost the same value (about 4Eh cycles
+apart).
+
+SPU Control
+ [1f801d80h]=37ef3fffh ;spu_main_vol ;[1f801da0h]=<random> ;spu_unk1
+ [1f801d84h]=5ebc5ebch ;spu_echo_vol [1f801da2h]=e128h ;spu_echo_base
+ [1f801d88h]=00000000h ;spu_key_on [1f801da4h]=0000h ;spu_irq_addr
+ [1f801d8ch]=00000c00h ;spu_key_off [1f801da6h]=0200h ;spu_xfer_addr
+ [1f801d90h]=00000000h ;spu_freqmod ;[1f801da8h]=0000h ;spu_xfer_fifo
+ [1f801d94h]=00000000h ;spu_noise [1f801daah]=c085h ;spu_cnt
+ [1f801d98h]=00ffffffh ;spu_reverb [1f801dach]=0004h ;spu_xfer_ctrl
+ [1f801d9ch]=00ffffcfh ;spu_on_off [1f801daeh]=0005h+bit11 ;spu_stat
+ [1f801db8h]=6fde7ffeh ;spu_curr_vol [1f801db0h]=0000h ;spu_cd_vol
+ ;[1f801dbch]=<random> ;spu_unk2 [1f801db4h]=0000h ;spu_aux_vol
+ ;[1f801e60h..7Fh]=<random> ;spu_unk3
+
+SPU Reverb (Echo)
+ [1f801dd4h]=1a311ed6h ;echo_m_same [1f801dc0h]=033dh ;echo_d_appf1
+ [1f801dd8h]=183b1d14h ;echo_m_comb1 [1f801dc2h]=0231h ;echo_d_appf2
+ [1f801ddch]=16b21bc2h ;echo_m_comb2 [1f801dc4h]=7e00h ;echo_v_iir
+ [1f801de0h]=15ef1a32h ;echo_d_same [1f801dc6h]=5000h ;echo_v_comb1
+ [1f801de4h]=105515eeh ;echo_m_diff [1f801dc8h]=b400h ;echo_v_comb2
+ [1f801de8h]=0f2d1334h ;echo_m_comb3 [1f801dcah]=b000h ;echo_v_comb3
+ [1f801dech]=0c5d11f6h ;echo_m_comb4 [1f801dcch]=4c00h ;echo_v_comb4
+ [1f801df0h]=0ae11056h ;echo_d_diff [1f801dceh]=b000h ;echo_v_wall
+ [1f801df4h]=07a20ae0h ;echo_m_apf1 [1f801dd0h]=6000h ;echo_v_apf1
+ [1f801df8h]=02320464h ;echo_m_apf2 [1f801dd2h]=5400h ;echo_v_apf2
+ [1f801dfch]=80008000h ;echo_v_in
+
+SPU Voice 0..23 (vol,rateaddr,adsr,stat, and currvol)
+Below are leftovers from PS-logo. Observe that some voices and ADSR generators
+are still running at time when starting the EXE file (some of that may depend
+on CDROM seek time and EXE file size).
+ [1f801c00h]=00000e7fh,02000bfch,dfed8c7ah,034c0000h [1f801e00h]=00001cfeh
+ [1f801c10h]=00000d0ch,02000aadh,dfed8c7ah,034c0000h [1f801e04h]=00001a18h
+ [1f801c20h]=0b740000h,02000c12h,dfed8c7ah,034c0000h [1f801e08h]=16e80000h
+ [1f801c30h]=05420000h,02000ac1h,dfed8c7ah,034c0000h [1f801e0ch]=0a840000h
+ [1f801c40h]=00001548h,0200017fh,cfaeb8ffh,034c4c41h [1f801e10h]=00002a90h
+ [1f801c50h]=16ab0000h,02000182h,cfaeb8ffh,034c4c41h [1f801e14h]=2d560000h
+ [1f801c60h]=00003e03h,0c2802abh,dff18088h,14c40faeh [1f801e18h]=00007c06h
+ [1f801c70h]=0000089eh,02001000h,dfed8c7ah,034c0000h [1f801e1ch]=0000113ch
+ [1f801c80h]=000005f4h,02000400h,dfed8c7ah,034c0000h [1f801e20h]=00000be8h
+ [1f801c90h]=02660000h,02000407h,dfed8c7ah,034c0000h [1f801e24h]=04cc0000h
+ [1f801ca0h]=00000bf7h,02000200h,cfaeb8ffh,034c0000h [1f801e28h]=000017eeh
+ [1f801cb0h]=0cc00000h,02000203h,cfaeb8ffh,034c0000h [1f801e2ch]=19800000h
+ [1f801cc0h]=00000735h,02000720h,dfed8c7ah,034c0000h [1f801e30h]=00000e6ah
+ [1f801cd0h]=05b10000h,0200072dh,dfed8c7ah,034c0000h [1f801e34h]=0b620000h
+ [1f801ce0h]=0000076fh,02000983h,dfed8c7ah,034c0000h [1f801e38h]=00000edeh
+ [1f801cf0h]=0a640000h,02000995h,dfed8c7ah,034c0000h [1f801e3ch]=14c80000h
+ [1f801d00h]=00000455h,02000aadh,dfed8c7ah,034c0000h [1f801e40h]=000008aah
+ [1f801d10h]=0c0d0000h,02000ac1h,dfed8c7ah,034c0000h [1f801e44h]=181a0000h
+ [1f801d20h]=00002171h,0c280556h,dff18088h,14c40fb8h [1f801e48h]=000042e2h
+ [1f801d30h]=0c0d0000h,0200101dh,dfed8c7ah,034c0000h [1f801e4ch]=181a0000h
+ [1f801d40h]=00000b43h,02000e41h,dfed8c7ah,034c0000h [1f801e50h]=00001686h
+ [1f801d50h]=0fbd0000h,02000e5bh,dfed8c7ah,034c0000h [1f801e54h]=1f7a0000h
+ [1f801d60h]=00000893h,02000800h,dfed8c7ah,034c0000h [1f801e58h]=00001126h
+ [1f801d70h]=06c70000h,0200080eh,dfed8c7ah,034c0000h [1f801e5ch]=0d8e0000h
+
+BIOS Versions
+-------------
+
+Kernel Versions
+For the actual kernel, there seem to be only a few different versions. Most
+PSX/PSone's are containing the version from 1995 (which is kept 1:1 the same in
+all consoles; without any PAL/NTSC related customizations).
+ 28-Jul-1994 "DTL-H2000" ;v0.x (pre-retail devboard)
+ 22-Sep-1994 "CEX-1000 KT-3 by S.O." ;v1.0 through v2.0
+ no-new-date "CEX-3000 KT-3 by K.S." ;v2.1 only (old Port 1F801060h)
+ 04-Dec-1995 "CEX-3000/1001/1002 by K.S." ;v2.2 through v4.5 (except v4.0)
+ 29-May-1997 "CEX-7000/-7001 by K.S. " ;v4.0 only (new Port 1F801010h)
+ 17-Jan-2000 "PS compatible mode by M.T." ;v5.0 (Playstation 2)
+The date and version string can be retrieved via GetSystemInfo(index).
+The "CEX-7000/-7001" version was only "temporarily" used (when the kernel/gui
+grew too large they changed the ROM size from 512K to 1024K; but did then
+figure out that they could use a self-decompressing GUI to squeeze everything
+into 512K; but they did accidentally still use the 1024K setting) (newer
+consoles fixed that and switched back to the old version from 1995) (aside from
+the different date/version string, the only changed thing is the opcode at
+BFC00000h, which initializes port 1F801010h to BIOS ROM size of 1MB, instead of
+512KB; no idea if that BIOS does actually contain additional data?).
+The "CEX-3000 KT-3" version is already almost same as "CEX-3000/1001/1002",
+aside from version/date, the only differences are at offset BFC00014h..1Fh, and
+BFC003E0h (both related to Port 1F801060h).
+
+Bootmenu/Intro Versions
+This portion was updated more often. It's customized for PAL/NTSC displays,
+japanese/english language, and (maybe?) region/licence string checks. The
+SCPH1000 uses uncompressed Bootmenu/Intro code with "<S>" intro and "PS" intro
+(although "PS" is shown only on region matches), newer versions are using
+selfdecompressing code. The GUI in older PSX models looks like a drawing
+program for children, the GUI in newer PSX models and in PSone's looks more
+like a modernized bathroom furniture, unknown how the PS2 GUI looks like?
+Games are communicating only with the Kernel, so the differences in the
+Bootmenu/Intro part should have little or effect on compatibility (although
+some I/O ports might be initialized differently, and although some games might
+(accidently) read different (garbage) values from the ROM).
+ Ver CRC32 Used in System ROM Version Kernel
+ 0.xj 18D0F7D8 DTL-H2000 (no version string) dtlh2000
+ 1.0j 3B601FC8 SCPH-1000 and DTL-H1000 (no version string) cex1000
+ 1.1j 3539DEF6 SCPH-3000 and DTL-H1000H "1.1 01/22/95" ""
+ 2.0a 55847D8C DTL-H1001 "2.0 05/07/95 A" ""
+ 2.0e 9BB87C4B SCPH-1002 and DTL-H1002 "2.0 05/10/95 E" ""
+ 2.1j BC190209 SCPH-3500 "2.1 07/17/95 J" cex3000
+ 2.1a AFF00F2F SCPH-1001 and DTL-H1101 "2.1 07/17/95 A" ""
+ 2.1e 86C30531 SCPH-1002 and DTL-H1102 "2.1 07/17/95 E" ""
+ 2.2j 24FC7E17 SCPH-5000 and DTL-H1200 "2.2 12/04/95 J" cex3000/100x
+ 2.2a 37157331 SCPH-1001 and DTL-H1201/3001 "2.2 12/04/95 A" ""
+ 2.2e 1E26792F SCPH-1002 and DTL-H1202/3002 "2.2 12/04/95 E" ""
+ 2.2v 446EC5B2 SCPH-5903 (VCD, 1Mbyte) "2.2 12/04/95 J" ""
+ 2.2d DECB22F5 DTL-H1100 "2.2 03/06/96 D" ""
+ 3.0j FF3EEB8C SCPH-5500 "3.0 09/09/96 J" ""
+ 3.0a 8D8CB7E4 SCPH-5501/7003 "3.0 11/18/96 A" ""
+ 3.0e D786F0B9 SCPH-5502/5552 "3.0 01/06/97 E" ""
+ 4.0j EC541CD0 SCPH-7000/9000 "4.0 08/18/97 J" cex7000
+ 4.1w B7C43DAD SCPH-7000W ...XXX...
+ 4.1a 502224B6 SCPH-7001/7501/7503/9001 "4.1 12/16/97 A" cex3000/100x
+ 4.1e 318178BF SCPH-7002/7502/9002 "4.1 12/16/97 E" ""
+ 4.3j F2AF798B SCPH-100 (PSone) "4.3 03/11/00 J" ""
+ 4.4a 6A0E22A0 SCPH-101 (PSone) "4.4 03/24/00 ..XXX..
+ 4.4e 0BAD7EA9 SCPH-102 (PSone) "4.4 03/24/00 E" ""
+ 4.5a 171BDCEC SCPH-101 (PSone) "4.5 05/25/00 A" ""
+ 4.5e 76B880E5 SCPH-102 (PSone) "4.5 05/25/00 E" ""
+ 5.0t B7EF81A9 SCPH10000 (Playstation 2) "5.0 01/17/00 T" PS compatible
+The System ROM Version string can be found at BFC7FF32h (except in v1.0).
+
+v2.2j/a/e use exactly the same GUI as v2.1 (only the kernel was changed). v2.2d
+is almost same as v2.2j (but with some GUI patches or so).
+v4.1 and v4.5 use exactly the same GUI code for "A" and "E" regions (the only
+difference is the last byte of the version string; which does specify whether
+the GUI shall use PAL or NTSC).
+v5.0 is playstation 2 bios (4MB) with more or less backwards compatible kernel.
+
+Character Set Versions
+The 16x15 pixel charsets at BFC66000h and BFC69D68h are included in all BIOSes,
+however, the 16x15 portion for letters with accent marks at BFC64000h is
+included only in non-japanese BIOSes, and in some newer japanese BIOSes (not
+included in v4.0j, but they are included in v4.3j).
+The 8x15 pixel charset with characters 21h..7Fh is included in all BIOSes. In
+the SCPH1000, this region is followed by additional 8x15 punctuation marks at
+char 80h and up, however, this region is missing in PS2 BIOS. Moreover, some
+BIOSes include an incomplete 8x15 japanese character set (which ends abruptly
+at BF7FFFFFh), in newer BIOSes, some of theses chars are replaced by the
+version string at BFC7FF32h, and, the remaining 8x15 japanese chars were
+removed in the PS2 BIOS version.
+
+BIOS Patches
+------------
+
+The original PSX Kernel mainly consists of messy and unstable compiler
+generated code, and, to the worst, the <same> author seems to have attempted to
+use assembler code in some places. In result, most commercial games are causing
+a greater mess by inserting patches in the kernel code...
+Which has been a nasty surprise when making the nocash PSX bios; which
+obviously wasn't compatible with these patches. The only solutions would have
+been to insert hundreds of NOPs to make my bios <exactly> as bloated as the
+original bios (which I really didn't want to do), or to create
+anti-patch-patches.
+
+Patches and Anti-Patch-Patches
+As shown below, all known patches are invoked by a B(56h) or B(57h) function
+call. In the nocash PSX bios, these two functions are examining the following
+opcodes, if the opcodes are a known patch, then the BIOS reproduces the desired
+behaviour, and does then continue normal execution after those opcodes. If the
+opcodes are unknown, then the BIOS simply locks up; and shows an error message
+with the address of that opcodes in the TTY window; info about any such unknown
+opcodes would be welcome!
+
+Compatibility
+If you want to (or need to) use patches, please use byte-identical opcodes as
+commercial games do (as shown below; only the "xxxx" address digits are don't
+care), so the nocash PSX bios (or other homebrewn BIOSes) can detect and
+reproduce them. Or alternately, don't use the BIOS, and access I/O ports
+directly, which is much better and faster anyways.
+
+patch_missing_cop0r13_in_exception_handler:
+In newer Kernel version, the exception handler reads cop0r13/cause to r2,
+examines the Excode value in r2, and if the exception was caused by an
+interrupt, and if the next opcode (at EPC) is a GTE/COP2 command, then it does
+increment EPC by 4. The GTE commands are executed even if an interrupt occurs
+simultaneously, so, without adjusting EPC, the command would be executed twice.
+With some commands that'd just waste some clock cycles, with other commands it
+may cause data to be written twice to the GTE FIFOs, or may re-use the result
+from the 1st command execution as input to the 2nd execution.
+The old "CEX-1000 KT-3" Kernel version did examine r2, but it "forgot" to
+previously load cop0r13 to r2, so it did randomly examine a garbage value. The
+patch inserts the missing opcode, used in elo2 at 80033740h, and in Pandemonium
+II at 8007F3FCh:
+ 240A00B0 mov r10,0B0h ;\ 00000000 nop
+ 0140F809 call r10 ; 00000000 nop
+ 24090056 +mov r9,56h ;/ 241A0100 mov k0,100h
+ 3C0Axxxx mov r10,xxxx0000h ;\ 8F5A0008 mov k0,[k0+8h]
+ 3C09xxxx mov r9,xxxx0000h ; 00000000 nop
+ 8C420018 mov r2,[r2+06h*4] ;=C(06h) ; 8F5A0000 mov k0,[k0]
+ 254Axxxx add r10,xxxxh ;=@@new_data ; 00000000 nop
+ 2529xxxx add r9,xxxxh ;=@@new_data_end ;/ 235A0008 addt k0,8h
+ @@copy_lop: ;\ AF410004 mov [k0+4h],r1
+ 8D430000 mov r3,[r10] ; AF420008 mov [k0+8h],r2
+ 254A0004 add r10,4h ; AF43000C mov [k0+0Ch],r3
+ 24420004 add r2,4h ; AF5F007C mov [k0+7Ch],ra
+ 1549FFFC jne r10,r9,@@copy_lop ; 40026800 mov r2,cop0r13
+ AC43FFFC +mov [r2-4h],r3 ;/ 00000000 nop
+Alternately, same as above, but using k0/k1 instead of r10/r9, used in Ridge
+Racer at 80047B14h:
+ 240A00B0 mov r10,0B0h ;\ 00000000 nop
+ 0140F809 call r10 ; 00000000 nop
+ 24090056 +mov r9,56h ;/ 241A0100 mov k0,100h
+ 3C1Axxxx mov k0,xxxx0000h ;\ 8F5A0008 mov k0,[k0+8h]
+ 3C1Bxxxx mov k1,xxxx0000h ; 00000000 nop
+ 8C420018 mov r2,[r2+06h*4] ;=C(06h) ; 8F5A0000 mov k0,[k0]
+ 275Axxxx add k0,xxxxh ;=@@new_data ; 00000000 nop
+ 277Bxxxx add k1,xxxxh ;=@@new_data_end ;/ 235A0008 addt k0,8h
+ @@copy_lop: ;\ AF410004 mov [k0+4h],r1
+ 8F430000 mov r3,[k0] ; AF420008 mov [k0+8h],r2
+ 275A0004 add k0,4h ; AF43000C mov [k0+0Ch],r3
+ 24420004 add r2,4h ; AF5F007C mov [k0+7Ch],ra
+ 175BFFFC jne k0,k1,@@copy_lop ; 40026800 mov r2,cop0r13
+ AC43FFFC +mov [r2-4h],r3 ;/ 00000000 nop
+Alternately, slightly different code used in metal_gear_solid at 80095CC0h, and
+in alone1 at 800A3ECCh:
+ 24090056 mov r9,56h ;\
+ 240A00B0 mov r10,0B0h ; B(56h) GetC0Table
+ 0140F809 call r10 ;
+ 00000000 +nop ;/
+ 8C420018 mov r2,[r2+06h*4] ;=00000C80h = exception_handler = C(06h)
+ 00000000 nop
+ 24420028 add r2,28h
+ 00407821 mov r15,r2
+ 3C0Axxxx lui r10,xxxxh ;\@@ori_data ;\
+ 254Axxxx add r10,xxxxh ;/ ;
+ 3C09xxxx lui r9,xxxxh ;\@@ori_data_end ; @@ori_data:
+ 2529xxxx add r9,xxxxh ;/ ; AF410004 mov [k0+4h],r1
+ @@verify_lop: ; AF420008 mov [k0+8h],r2
+ 8D430000 mov r3,[r10] ; AF43000C mov [k0+0Ch],r3
+ 8C4B0000 mov r11,[r2] ; AF5F007C mov [k0+7Ch],ra
+ 254A0004 add r10,4h ; 40037000 mov r3,cop0r14
+ 146B000E jne r3,r11,@@verify_mismatch ; 00000000 nop
+ 24420004 +add r2,4h ;
+ 1549FFFA jne r10,r9,@@verify_lop ;
+ 00000000 +nop ;/
+ 01E01021 mov r2,r15
+ 3C0Axxxx lui r10,xxxxh ;\@@new_data ;\
+ 254Axxxx add r10,xxxxh ;/ ;
+ 3C09xxxx lui r9,xxxxh ;\@@new_data_end ; @@new_data:
+ 2529xxxx add r9,xxxxh ;/ ; AF410004 mov [k0+4h],r1
+ @@copy_lop: ; AF420008 mov [k0+8h],r2
+ 8D430000 mov r3,[r10] ; 40026800 mov r2,cop0r13
+ 00000000 nop ; AF43000C mov [k0+0Ch],r3
+ AC430000 mov [r2],r3 ; 40037000 mov r3,cop0r14
+ 254A0004 add r10,4h ; AF5F007C mov [k0+7Ch],ra
+ 1549FFFB jne r10,r9,@@copy_lop ;
+ 24420004 +add r2,4h ;/
+ @@verify_mismatch:
+Alternately, a bugged/nonfunctional homebrew variant (used by Hitmen's
+"minimum" demo):
+ ;BUG1: 8bit "movb r6" should be 32bit "mov r6"
+ ;BUG2: @@copy_lop should transfer 6 words (not 7 words)
+ ;BUG3: and, asides, the minimum demo works only with PAL BIOS (not NTSC)
+ 0xxxxxxx call xxxxxxxxh ;\B(56h) GetC0Table
+ 00000000 +nop ;/(mov r8,0B0h, jmp r8, +mov r9,56h)
+ 3C04xxxx mov r4,xxxx0000h ;\@@ori_data
+ 2484xxxx add r4,xxxxh ;/
+ 90460018 movb r6,[r2+06h*4] ;BUG1 ;exception_handler = C(06h)
+ 24870018 add r7,r4,18h ;@@ori_end ;\
+ 24C50028 add r5,r6,28h ;C(06h)+28h ;
+ 00A03021 mov r6,r5 ; @@ori_data:
+ @@verify_lop: ; 80086520 AF410004 mov [k0+4h],r1
+ 8CA30000 mov r3,[r5] ; 80086524 AF420008 mov [k0+8h],r2
+ 8C820000 mov r2,[r4] ; 80086528 AF43000C mov [k0+0Ch],r3
+ 00000000 nop ; 8008652C AF5F007C mov [k0+7Ch],ra
+ 1462000C jne r3,r2,@@verify_mismatch ; 80086530 40037000 mov r3,cop0r14
+ 24840004 +add r4,4h ; 80086534 00000000 nop
+ 1487FFFA jne r4,r7,@@verify_lop ; @@ori_end:
+ 24A50004 +add r5,4h ;/
+ 00C02821 mov r5,r6 ;\ @@new_data:
+ 3C04xxxx mov r4,xxxx0000h ;\@@new_data; 80086538 AF410004 mov [k0+4h],r1
+ 2484xxxx add r4,xxxxh ;/ ; 8008653C AF420008 mov [k0+8h],r2
+ 2483001C add r3,r4,1Ch ;@@bugged_end ; 80086540 40026800 mov r2,cop0r13
+ @@copy_lop: ; 80086544 AF43000C mov [k0+0Ch],r3
+ 8C820000 mov r2,[r4] ; 80086548 40037000 mov r3,cop0r14
+ 24840004 add r4,4h ; 8008654C AF5F007C mov [k0+7Ch],ra
+ ACA20000 mov [r5],r2 ; @@new_end:
+ 1483FFFC jne r4,r3,@@copy_lop ; 80086550 00000000 nop ;BUG2
+ 24A50004 +add r5,4h ;/ @@bugged_end:
+ @@verify_mismatch:
+
+early_card_irq_patch:
+Because of a hardware glitch the card IRQ cannot be acknowledged while the
+external IRQ signal is still LOW, making it neccessary to insert a delay that
+waits until the signal gets HIGH before acknowledging the IRQ.
+The original BIOS is so inefficient that it takes hundreds of clock cycles
+between the interrupt request and the IRQ acknowledge, so, normally, it doesn't
+require an additional delay.
+However, the central mistake in the IRQ handler is that it doesn't memorize
+which IRQ has originally triggered the interrupt. For example, it may get
+triggered by a timer IRQ, but a newer card IRQ may occur during IRQ handling,
+in that case, the card IRQ may get processed and acknowledged without the
+required delay.
+Used in Metal Gear Solid at 8009AA5Ch, and in alone1 at 800AE2F8h:
+ 24090056 mov r9,56h ;\ ; @@new_data:
+ 240A00B0 mov r10,0B0h ; B(56h) GetC0Table ;3C02A001 lui r2,0A001h
+ 0140F809 call r10 ; ;2442DFAC sub r2,2054h
+ 00000000 +nop ;/ ;00400008 jmp r2 ;=@@new_cont_d
+ 8C420018 mov r2,[r2+06h*4] ;\get C(06h) ;00000000 +nop ;=A000DFACh
+ 00000000 nop ;/ ;00000000 nop
+ 8C430070 mov r3,[r2+70h] ;\ ; @@new_data_end:
+ 00000000 nop ; get ; @@new_cont_d:
+ 3069FFFF and r9,r3,0FFFFh ; early_card ;8C621074 mov r2,[r3+1074h]
+ 00094C00 shl r9,10h ; irq_handler ;00000000 nop
+ 8C430074 mov r3,[r2+74h] ; ;30420080 and r2,80h ;I_STAT.7
+ 00000000 nop ; ;1040000B jz r2,@@ret
+ 306AFFFF and r10,r3,0FFFFh ;/ ;00000000 +nop
+ 012A1821 add r3,r9,r10 ; @@wait_lop:
+ 24620028 add r2,r3,28h ;=early+28h ;8C621044 mov r2,[r3+1044h]
+ 3C0Axxxx lui r10,xxxxh ;\@@new_data ;00000000 nop
+ 254Axxxx sub r10,xxxxh ;/ ;30420080 and r2,80h ;JOY_STAT.7
+ 3C09xxxx lui r9,xxxxh ;\@@new_data_end ;1440FFFC jnz r2,@@wait_lop
+ 2529xxxx sub r9,xxxxh ;/ ;00000000 +nop
+ @@copy_lop: ;3C020001 lui r2,0001h
+ 8D430000 mov r3,[r10] ;8C42DFFC mov r2,[r2-2004h]
+ 00000000 nop ;00000000 nop
+ AC430000 mov [r2],r3 ;00400008 jmp r2 ;=[0000DFFCh]
+ 254A0004 add r10,4h ;00000000 +nop
+ 1549FFFB jne r10,r9,@@copy_lop ; @@ret:
+ 24420004 +add r2,4h ;03E00008 ret
+ 3C010001 lui r1,0001h ;\[DFFCh]=r2 ;00000000 +nop
+ 0xxxxxxx call xxxxxxxxh ; and call ... ;
+ AC22DFFC +mov [r1-2004h],r2 ;/ ;
+Alternately, elo2 uses slightly different code at 8003961Ch:
+ 240A00B0 mov r10,0B0h ;\ ; @@new_data:
+ 0140F809 call r10 ; B(56h) GetC0Table ;3C02xxxx lui r2,8xxxh
+ 24090056 +mov r9,56h ;/ ;2442xxxx sub r2,xxxxh
+ 8C420018 mov r2,[r2+06h*4] ;\get C(06h) ;00400008 jmp r2 ;=@@new_cont_d
+ 00000000 nop ;/ ;00000000 +nop ;=8xxxxxxxh
+ 8C430070 mov r3,[r2+70h] ;\ ;00000000 nop
+ 00000000 nop ; get ; @@new_data_end:
+ 3069FFFF and r9,r3,0FFFFh ; early_card ; @@new_cont_d:
+ 8C430074 mov r3,[r2+74h] ; irq_handler ;8C621074 mov r2,[r3+1074h]
+ 00094C00 shl r9,10h ; ;00000000 nop
+ 306AFFFF and r10,r3,0FFFFh ; ;30420080 and r2,80h ;I_STAT.7
+ 012A1821 add r3,r9,r10 ;/ ;1040000B jz r2,@@ret
+ 3C0Axxxx mov r10,xxxx0000h ;00000000 +nop
+ 3C09xxxx mov r9,xxxx0000h ; @@wait_lop:
+ 24620028 add r2,r3,28h ;=early+28h ;8C621044 mov r2,[r3+1044h]
+ 254Axxxx sub r10,xxxxh ;=@@new_data ;00000000 nop
+ 2529xxxx sub r9,xxxxh ;=@@new_data_end ;30420080 and r2,80h ;JOY_STAT.7
+ @@copy_lop: ;1440FFFC jnz r2,@@wait_lop
+ 8D430000 mov r3,[r10] ;00000000 +nop
+ 254A0004 add r10,4h ;3C02xxxx lui r2,8xxxh
+ 24420004 add r2,4h ;8C42xxxx mov r2,[r2-xxxxh]
+ 1549FFFC jne r10,r9,@@copy_lop ;00000000 nop
+ AC43FFFC +mov [r2-4h],r3 ;00400008 jmp r2 ;=[8xxxxxxxh]
+ 3C018xxx mov r1,8xxx0000h ;\[...]=r2, ;00000000 +nop
+ 0xxxxxxx call xxxxxxxxh ; and call ... ; @@ret:
+ AC22xxxx +mov [r1+xxxxh],r2 ;/ ;03E00008 ret
+ ... ;00000000 +nop
+Note: The above @@wait_lop's should be more preferably done with timeouts (else
+they may hang endless if a Sony Mouse is newly connected; the mouse does have
+/ACK stuck LOW on power-up).
+
+patch_uninstall_early_card_irq_handler:
+Used to uninstall the "early_card_irq_vector" (the BIOS installs that vector
+from inside of B(4Ah) InitCard(pad_enable), and, without patches, the BIOS
+doesn't allow to uninstall it thereafter).
+Used in Breath of Fire III (SLES-01304) at 8017E790, and also in Ace Combat 2
+(SLUS-00404) at 801D23F4:
+ 240A00B0 mov r10,0B0h ;\
+ 0140F809 call r10 ; B(56h) GetC0Table
+ 24090056 +mov r9,56h ;/
+ 3C0Axxxx mov r10,xxxx0000h
+ 3C09xxxx mov r9,xxxx0000h
+ 8C420018 mov r2,[r2+06h*4] ;=00000C80h = exception_handler = C(06h)
+ 254Axxxx add r10,xxxxh ;@@new_data
+ 2529xxxx add r9,xxxxh ;@@new_data_end
+ @@copy_lop: ;\ @@new_data:
+ 8D430000 mov r3,[r10] ; 00000000 nop
+ 254A0004 add r10,4h ; 00000000 nop
+ 24420004 add r2,4h ; 00000000 nop
+ 1549FFFC jne r10,r9,@@copy_lop ; @@new_data_end:
+ AC43006C +mov [r2+70h-4],r3 ;/
+Alternately, more inefficient, used in Blaster Master-Blasting Again
+(SLUS-01031) at 80063FF4h, and Raiden DX at 80029694h:
+ 24090056 mov r9,56h ;\
+ 240A00B0 mov r10,0B0h ; B(56h) GetC0Table
+ 0140F809 call r10 ;
+ 00000000 +nop ;/
+ 8C420018 mov r2,[r2+06h*4] ;=00000C80h = exception_handler = C(06h)
+ 3C0Axxxx mov r10,xxxx0000h ;\@@new_data
+ 254Axxxx add r10,xxxxh ;/
+ 3C09xxxx mov r9,xxxx0000h ;\@@new_data_end
+ 2529xxxx add r9,xxxxh ;/
+ @@copy_lop: ;\
+ 8D430000 mov r3,[r10] ; @@new_data:
+ 00000000 nop ; 00000000 nop
+ AC430070 mov [r2+70h],r3 ; 00000000 nop
+ 254A0004 add r10,4h ;src ; 00000000 nop
+ 1549FFFB jne r10,r9,@@copy_lop ; @@new_data_end:
+ 24420004 +add r2,4h ;dst ;/
+Note: the above code is same as "patch_install_lightgun_irq_handler", except
+that it writes to r2+70h, instead of r2+80h.
+
+patch_card_specific_delay:
+Same purpose as the "early_card_irq_patch" (but for the command/status bytes
+rather than for the data bytes). The patch looks buggy since it inserts the
+delay AFTER the acknowledge, but it DOES work (the BIOS accidently acknowledges
+the IRQ twice; and the delay occurs PRIOR to 2nd acknowledge).
+Used in Metal Gear Solid at 8009AAF0h, and in Legacy of Kain at 801A56D8h, and
+in alone1 at 800AE38Ch:
+ 24090057 mov r9,57h ;\ ; @@new_data:
+ 240A00B0 mov r10,0B0h ; B(57h) GetB0Table ; 3C08A001 lui r8,0A001h
+ 0140F809 call r10 ;/ ; 2508DF80 sub r8,2080h
+ 00000000 +nop ; 0100F809 call r8 ;=A000DF80h
+ 8C42016C mov r2,[r2+5Bh*4] ;B(5Bh) ; 00000000 +nop
+ 00000000 nop ; 00000000 nop
+ 8C4309C8 mov r3,[r2+9C8h] ;blah ; @@new_data_end:
+ 3C0Axxxx lui r10,xxxxh ;\@@new_data ; 946F000A movh r15,[r3+0Ah]
+ 254Axxxx sub r10,xxxxh ;/ ; 3C080000 mov r8,0h
+ 3C09xxxx lui r9,xxxxh ;\@@new_data_end ; 01E2C025 or r24,r15,r2
+ 2529xxxx sub r9,xxxxh ;/ ; 37190012 or r25,r24,12h
+ @@copy_lop: ; A479000A movh [r3+0Ah],r25
+ 8D480000 mov r8,[r10] ; 24080028 mov r8,28h
+ 00000000 nop ; @@wait_lop:
+ AC4809C8 mov [r2+9C8h],r8 ;B(5Bh)+9C8h.. ; 2508FFFF sub r8,1h
+ 254A0004 add r10,4h ; 1500FFFE jnz r8,@@wait_lop
+ 1549FFFB jne r10,r9,@@copy_lop ; 00000000 +nop
+ 24420004 +add r2,4h ; 03E00008 ret ;above delay is
+ ... ; 00000000 +nop ;in UNCACHED RAM
+Alternately, slightly different code used in elo2 at800396D4h, and in Resident
+Evil 2 at 800910E4h:
+ 240A00B0 mov r10,0B0h ;\ ; @@swap_begin:
+ 0140F809 call r10 ; B(57h) GetB0Table ; 3C088xxx lui r8,8xxxh
+ 24090057 +mov r9,57h ;/ ; 2508xxxx sub r8,xxxxh
+ 8C42016C mov r2,[r2+5Bh*4] ;B(5Bh) ; 0100F809 call r8 ;=8xxxxxxxh
+ 3C0Axxxx mov r10,xxxx0000h ; 00000000 +nop
+ 3C09xxxx mov r9,xxxx0000h ; 00000000 nop
+ 8C4309C8 mov r3,[r2+9C8h] ;blah ; @@swap_end:
+ 254Axxxx sub r10,xxxxh ;=@@swap_begin ; ;- - -
+ 2529xxxx sub r9,xxxxh ;=@@swap_end ; 00000000 nop
+ @@swap_lop: ; 240800C8 mov r8,0C8h
+ 8C4309C8 mov r3,[r2+9C8h] ;B(5Bh)+9C8h.. ; @@wait_lop:
+ 8D480000 mov r8,[r10] ; 2508FFFF sub r8,1h
+ 254A0004 add r10,4h ; 1500FFFE jnz r8,@@wait_lop
+ AD43FFFC mov [r10-4h],r3 ; 00000000 +nop
+ 24420004 add r2,4h ; 03E00008 ret ;above delay is
+ 1549FFFA jne r10,r9,@@swap_lop ; 00000000 +nop ;in CACHED RAM
+ AC4809C4 +mov [r2+9C4h],r8 ;
+
+patch_card_info_step4:
+The "card_info" function sends an incomplete read command to the card; in order
+to receive status information. After receiving the last byte, the function does
+accidently send a further byte to the card, so the card responds by another
+byte (and another IRQ7), which is not processed nor acknowledged by the BIOS.
+This patch kills the opcode that sends the extra byte.
+Used in alone1 at 800AE214h:
+ 24090057 mov r9,57h ;\
+ 240A00B0 mov r10,0B0h ; B(57h) GetB0Table
+ 0140F809 call r10 ;
+ 00000000 +nop ;/
+ 240A0009 mov r10,9h ;=blah
+ 8C42016C mov r2,[r2+5Bh*4] ;=B(5Bh)
+ 00000000 nop
+ 20431988 addt r3,r2,1988h ;=B(5Bh)+1988h ;\store a NOP,
+ 0xxxxxxx call xxxxxxxxh ; and call ...
+ AC600000 +mov [r3],0 ;=nop ;/
+
+patch_pad_error_handling_and_get_pad_enable_functions:
+If a transmission error occurs (or if there's no controller connected), then
+the Pad handler handler does usually issue a strange chip select signal to the
+OTHER controller slot, and does then execute the bizarre_pad_delay function.
+The patch below overwrites that behaviour by NOPs. Purpose of the original (and
+patched) behaviour is unknown.
+Used by Perfect Assassin at 800519D4h:
+ 240A00B0 mov r10,0B0h ;\
+ 0140F809 call r10 ; B(57h) GetB0Table
+ 24090057 +mov r9,57h ;/
+ 8C42016C mov r2,[r2+5Bh*4] ;=B(5Bh)
+ 3C01xxxx mov r1,xxxx0000h
+ 20430884 addt r3,r2,884h ;B(5Bh)+884h
+ AC23xxxx mov [r1+xxxxh],r3 ;<--- SetPadEnableFlag()
+ 3C01xxxx mov r1,xxxx0000h
+ 20430894 addt r3,r2,894h ;B(5Bh)+894h
+ 2409000B mov r9,0Bh ;len
+ AC23xxxx mov [r1+xxxxh],r3 ;<--- ClearPadEnableFlag()
+ @@fill_lop: ;\
+ 2529FFFF sub r9,1h ;
+ AC400594 mov [r2+594h],0 ;B(5Bh)+594h.. ; erase error handling
+ 1520FFFD jnz r9,@@fill_lop ;
+ 24420004 +add r2,4h ;/
+Alternately, same as above, but with inefficient nops, used by Sporting Clays
+at 8001B4B4h:
+ 24090057 mov r9,57h ;\
+ 240A00B0 mov r10,0B0h ; B(57h) GetB0Table
+ 0140F809 call r10 ;
+ 00000000 +nop ;/
+ 8C42016C mov r2,[r2+5Bh*4]
+ 2409000B mov r9,0Bh ;len
+ 20430884 addt r3,r2,884h
+ 3C01xxxx mov r1,xxxx0000h
+ AC23xxxx mov [r1+xxxxh],r3 ;<--- SetPadEnableFlag()
+ 20430894 addt r3,r2,894h
+ 3C01xxxx mov r1,xxxx0000h
+ AC23xxxx mov [r1+xxxxh],r3 ;<--- ClearPadEnableFlag()
+ @@fill_lop: ;\
+ AC400594 mov [r2+594h],0 ;
+ 24420004 add r2,4h ; erase error handling
+ 2529FFFF sub r9,1h ;
+ 1520FFFC jnz r9,@@fill_lop ;
+ 00000000 +nop ;/
+Alternately, same as above, but without getting PadEnable functions, used in
+Pandemonium II (at 80083C94h and at 8010B77Ch):
+ 240A00B0 mov r10,0B0h ;\
+ 0140F809 call r10 ; B(57h) GetB0Table
+ 24090057 +mov r9,57h ;/
+ 8C42016C mov r2,[r2+5Bh*4] ;=B(5Bh)
+ 2409000B mov r9,0Bh ;len ;\
+ @@fill_lop: ;
+ 2529FFFF sub r9,1h ; erase error handling
+ AC400594 mov [r2+594h],0 ;B(5Bh)+594h.. ;
+ 1520FFFD jnz r9,@@fill_lop ;
+ 24420004 +add r2,4h ;/
+
+patch_optional_pad_output:
+The normal BIOS functions are only allowing to READ from the controllers, but
+not to SEND data to them (which would be required to control Rumble motors, and
+to auto-activate Analog mode without needing the user to press the Analog
+button). Internally, the BIOS does include some code for sending data to the
+controller, but it doesn't offer a function vector for setting up the data
+source address, and, even if that would be supported, it clips the data bytes
+to 00h or 01h. The patch below retrieves the required SetPadOutput function
+address (in which only the src1/src2 addresses are relevant, the blah1/blah2
+values aren't used), and suppresses clipping (ie. allows to send any bytes in
+range 00h..FFh).
+Used in Resident Evil 2 at 80091914h:
+ 240A00B0 mov r10,0B0h ;\
+ 0140F809 call r10 ; B(57h) GetB0Table
+ 24090057 +mov r9,57h ;/
+ 8C42016C mov r2,[r2+5Bh*4] ;B(5Bh)
+ 3C0Axxxx mov r10,xxxx0000h
+ 3C09xxxx mov r9,xxxx0000h
+ 3C01xxxx mov r1,xxxx0000h
+ 204307A0 addt r3,r2,7A0h ;B(5Bh)+7A0h
+ 254Axxxx add r10,xxxxh ;=@@new_data
+ 2529xxxx add r9,xxxxh ;=@@new_data_end
+ AC23xxxx mov [r1-xxxxh],r3 ;<--- SetPadOutput(src1,blah1,src2,blah2)
+ @@double_copy_lop: ;\
+ 8D430000 mov r3,[r10] ; @@new_data:
+ 254A0004 add r10,4h ; 00551024 and r2,r21
+ AC4303D8 mov [r2+3D8h],r3 ;<--- here ; 00000000 nop
+ 24420004 add r2,4h ; 00000000 nop
+ 1549FFFB jne r10,r9,@@double_copy_lop ; 00000000 nop
+ AC4304DC +mov [r2+4DCh],r3 ;<--- here ;/ @@new_data_end:
+Alternately, more inefficient (with NOPs), used in Lemmings at 80036618h:
+ 24090057 mov r9,57h ;\
+ 240A00B0 mov r10,0B0h ; B(57h) GetB0Table
+ 0140F809 call r10 ;
+ 00000000 +nop ;/
+ 3C0Axxxx mov r10,xxxx0000h
+ 254Axxxx add r10,xxxxh ;=@@new_data
+ 3C09xxxx movp r9,xxxx0000h
+ 2529xxxx add r9,xxxxh ;=@@new_data_end
+ 8C42016C mov r2,[r2+5Bh*4] ;B(5Bh)
+ 00000000 nop
+ 204307A0 addt r3,r2,7A0h ;B(5Bh)+7A0h
+ 3C01xxxx mov r1,xxxx0000h
+ AC23xxxx mov [r1+xxxxh],r3 ;<--- SetPadOutput(src1,blah1,src2,blah2)
+ @@double_copy_lop: ;\
+ 8D430000 mov r3,[r10] ; @@new_data:
+ 00000000 nop ; 00551024 and r2,r21
+ AC4303D8 mov [r2+3D8h],r3 ; 00000000 nop
+ AC4304E0 mov [r2+4E0h],r3 ; 00000000 nop
+ 24420004 add r2,4h ; 00000000 nop
+ 254A0004 add r10,4h ; @@new_data_end:
+ 1549FFF9 jne r10,r9,@@double_copy_lop ;
+ 00000000 +nop ;/
+
+patch_no_pad_card_auto_ack:
+This patch suppresses automatic IRQ0 (vblank) acknowleding in the Pad/Card IRQ
+handler, that, even if auto-ack is enabled. Obviously, one could as well
+disable auto-ack via B(5Bh) ChangeClearPad(int), so this patch is total
+nonsense. Used in Resident Evil 2 at 800919ACh:
+ 240A00B0 mov r10,0B0h ;\
+ 0140F809 call r10 ; B(57h) GetB0Table
+ 24090057 +mov r9,57h ;/
+ 8C42016C mov r2,[r2+5Bh*4] ;=B(5Bh)
+ 240A0009 mov r10,9h ;len ;\
+ 2043062C addt r3,r2,62Ch ;=B(5Bh)+62Ch ;
+ @@fill_lop: ;
+ 254AFFFF sub r10,1h ;
+ AC600000 mov [r3],0 ;
+ 1540FFFD jnz r10,@@fill_lop ;
+ 24630004 +add r3,4h ;/
+Alternately, same as above, but more inefficient, used in Sporting Clays at
+8001B53Ch:
+ 24090057 mov r9,57h ;\
+ 240A00B0 mov r10,0B0h ; B(57h) GetB0Table
+ 0140F809 call r10 ;
+ 00000000 +nop ;/
+ 240A0009 mov r10,9h ;len
+ 8C42016C mov r2,[r2+5Bh*4]
+ 00000000 nop
+ 2043062C addt r3,r2,62Ch
+ @@fill_lop: ;\
+ AC600000 mov [r3],0 ;
+ 24630004 add r3,4h ;
+ 254AFFFF sub r10,1h ;
+ 1540FFFC jnz r10,@@fill_lop ;
+ 00000000 +nop ;/
+Either way, no matter if using the patch or if using ChangeClearPad(int),
+having auto-ack disabled allows to install a custom vblank IRQ0 handler, which
+is probably desired for most games, however, mind that the PSX BIOS doesn't
+actually support the same IRQ to be processed by two different IRQ handlers,
+eg. the custom handler may acknowledge the IRQ even when the Pad/Card handler
+didn't process it, so pad input may become bumpy.
+
+patch_install_lightgun_irq_handler:
+Used in Sporting Clays at 80027D68h (when Konami Lightgun connected):
+ 240A00B0 mov r10,0B0h ;\
+ 0140F809 call r10 ; B(56h) GetC0Table
+ 24090056 +mov r9,56h ;/
+ 3C0Axxxx mov r10,xxxx0000h ;src
+ 3C09xxxx mov r9,xxxx0000h ;src.end
+ 8C420018 mov r2,[r2+06h*4] ;C(06h) ;=00000C80h = exception_handler
+ 254Axxxx add r10,xxxxh ;src
+ 2529xxxx add r9,xxxxh ;src.end (=src+10h)
+ @@copy_lop: ;\ ; @@src:
+ 8D430000 mov r3,[r10] ; ;3C02xxxx mov r2,xxxx0000h
+ 254A0004 add r10,4h ; ;2442xxxx add r2,xxxxh
+ 24420004 add r2,4h ; ;0040F809 call r2 ;lightgun_proc
+ 1549FFFC jne r10,r9,@@copy_lop ; ;00000000 +nop
+ AC43007C +mov [r2+80h-4],r3 ;/ @@src_end:
+Alternately, same as above, using k0/k1, used in Star Wars Rebel Assault II
+(The Hidden Empire) at 800942B0h (install) and 80094308h (uninstall):
+ 240A00B0 mov r10,0B0h ;\
+ 0140F809 call r10 ; B(56h) GetC0Table
+ 24090056 +mov r9,56h ;/
+ 3C1Axxxx mov k0,xxxx0000h ;src
+ 3C1Bxxxx mov k1,xxxx0000h ;src.end (=src+10h)
+ 8C420018 mov r2,[r2+06h*4] ;C(06h) ;=00000C80h = exception_handler
+ 275Axxxx add k0,xxxxh ;src ;=8009438Ch
+ 277Bxxxx add k1,xxxxh ;src.end
+ @@copy_lop: ;\@@new_data: ;for (un-)install...
+ 8F430000 mov r3,[k0] ; 00000000 nop / 3C02xxxx mov r2,xxxx0000h
+ 275A0004 add k0,4h ; 00000000 nop / 2442xxxx add r2,-xxxxh
+ 24420004 add r2,4h ; 00000000 nop / 0040F809 call r2 ;proc
+ 175BFFFC jne k0,k1,@@copy_lop ; 00000000 nop / 00000000 +nop
+ AC43007C +mov [r2+80h-4],r3 ;/@@new_data_end:
+Alternately, same as above, but more inefficient, used in DQM (Dragon Quest
+Monsters 1&2) at 80089390h (install) and 800893F8h (uninstall):
+ 24090056 mov r9,56h ;\
+ 240A00B0 mov r10,0B0h ; B(56h) GetC0Table
+ 0140F809 call r10 ;
+ 00000000 +nop ;/
+ 8C420018 mov r2,[r2+06h*4] ;C(06h) ;=00000C80h = exception_handler
+ 3C0Axxxx mov r10,xxxx0000h ;\@@new_data (3xNOP)
+ 254Axxxx add r10,-xxxxh ;/
+ 3C09xxxx mov r9,xxxx0000h ;\@@new_data_end
+ 2529xxxx add r9,-xxxxh ;/
+ @@copy_lop: ;\
+ 8D430000 mov r3,[r10] ; @@new_data: ;for (un-)install...
+ 00000000 nop ; 00000000 nop / 3C02xxxx mov r2,xxxx0000h
+ AC430080 mov [r2+80h],r3 ; 00000000 nop / 2442xxxx add r2,-xxxxh
+ 254A0004 add r10,4h ; 00000000 nop / 0040F809 call r2 ;proc
+ 1549FFFB jne r10,r9,@@copy_lop ; @@new_data_end:
+ 24420004 +add r2,4h ;/
+Some lightgun games (eg. Project Horned Owl) do (additionally to above stuff)
+hook the exception vector at 00000080h (aka 80000080h), the hook copies the
+horizontal coordinate (timer0) to a variable in RAM, thus getting the timer0
+value "closest" to the actual IRQ execution. Doing that may eliminate some
+unpredictable timing offsets that could be caused by cache hits/misses during
+later IRQ handling (and may also eliminate a rather irrelevant 1-cycle
+inaccuracy depending on whether EPC was pointing to a GTE opcode, and also
+eliminates constant cycle offsets depending on whether early_card_irq_handler
+was installed and enabled, and might eliminate timing differences for different
+BIOS versions).
+
+set_conf_without_realloc:
+Used in Spec Ops Airborne Commando at 80070AE8h, and also in the homebrew game
+Roll Boss Rush at 80010B68h and 8001B85Ch. Purpose is unknown (maybe to
+override improperly defined .EXE headers).
+ 8C030474 mov r3,[200h+(9Dh*4)] ;\get ptr to A(9Dh) GetConf (done so,
+ 00000000 nop ;/as there's no "GetA0Table" funtion)
+ 94620000 movh r2,[r3+0h] ;lui msw ;\
+ 84630004 movhs r3,[r3+4h] ;lw lsw+8 ; extract ptr to "boot_cnf_values"
+ 00021400 shl r2,10h ;msw*10000h ; (from first 2 opcodes of GetConf)
+ 2442FFF8 sub r2,8h ;undo +8 ;
+ 00431021 add r2,r3 ;lsw ;/
+ AC450000 mov [r2+0h],r5 ;num_TCB ;\set num_EvCB,num_TCB,stacktop
+ AC440004 mov [r2+4h],r4 ;num_EvCB ; (unlike A(9Ch) SetConf, without
+ 03E00008 ret ; actually reallocting anything)
+ AC460008 +mov [r2+8h],r6 ;stacktop ;/
+
+Cheat Devices
+CAETLA detects the PSX BIOS version by checksumming BFC06000h..BFC07FFFh and
+does then use some hardcoded BIOS addresses based on that checksum. The reason
+for doing that is probably that the Pre-Boot Expansion ROM vector is called
+with the normal A0h/B0h/C0h vectors being still uninitialized.
+Problems are that the hardcoded addresses won't work with all BIOSes (eg. not
+with the no$psx bios clone, probably also not with the newer PS2 BIOS),
+moreover, the checksumming can fail with patched original BIOSes (eg. no$psx
+allows to enable TTY debug messages and to skip the BIOS intro).
+The Cheat Firmwares are probably also hooking the Vblank handler, and maybe
+also some other functions.
+ACTION REPLAY (at least later versions like 2.81) uses the Pre-Boot handler to
+set a COP0 hardware breakpoint at 80030000h and does then resume normal BIOS
+booting (which will then initialize important things like A0h/B0h/C0h tables,
+and will then break when starting the GUI code at 80030000h).
+XPLORER searches opcode 24040385h at BFC06000h and up, and does then place a
+COP0 opcode fetch breakpoint at the opcode address+10h (note: this is within a
+branch delay slot, which makes COP0 emulation twice as complicated). XPLORER
+does also require space in unused BIOS RAM addresses (eg. Xplorer v3.20: addr
+7880h at 1F002280h, addr 017Fh at 1F006A58h).
+
+Note
+Most games include two or three patches. The only game that I've seen so far
+that does NOT use any patches is Wipeout 2097.
+
+Arcade Cabinets
+---------------
+
+PSX-Based Arcade Boards
+ Namco System 11, System 12 (and System 10?)
+ Capcom/Sony ZN-1, ZN-2
+ Konami GV, Konami GQ
+ Taito FX-1A, Taito FX-1B
+ Atlus PSX, PS Arcade 95, Tecmo TPS
+
+CPU
+Same as in PSX. Except, one board is said to be having the CPU clocked at
+48MHz, instead of 33MHz???
+
+GPU
+Same as in PSX. Except, most or all boards are said to have 2MB VRAM instead of
+1MB. Unknown how the extra VRAM is accessed... maybe as Y=512..1023... (though
+the PSX VRAM transfer commands are limited to 9bit Ysiz values, but maybe Y
+coordinates can be 10bit wide).
+
+ROM vs CDROM
+Arcade games are stored on ROM (or FLASH) instead of using CDROM drives.
+
+SPU
+Most PSX-based arcade boards are having the PSX-SPU replaced by a different
+sound chip (with each arcade manufacturer using their own custom sound chip,
+often controlled by a separate sound CPU).
+
+Controls
+Arcade boards are typically having digital joysticks instead of joypads, with
+differently named buttons (instead of /\,[],(),><), probably accessed via
+custom I/O ports (instead of serial transmission)? Plus additional coin inputs
+and DIP switches.
+
+Note: There's no documentation for those arcade boards yet, however, it might
+be possible to extract that info from MAME source code.
+
+Cheat Devices
+-------------
+
+Action Replay, GameShark, Gamebuster, GoldFinger, Equalizer (Datel/clones)
+The Datel devices exist in various official/cloned hardware revisions, the DB25
+connector requires a special Comms Link ISA card (or a "FiveWire" mod for
+making it compatible with normal PC parallel ports). Later "PAR3" models are
+said to not require Comms Link, and do thus probably work directly with normal
+parallel ports).
+--> Cheat Devices - Datel I/O
+--> Cheat Devices - Datel DB25 Comms Link Protocol
+--> Cheat Devices - Datel Chipset Pinouts
+--> Cheat Devices - Datel Cheat Code Format
+
+Xplorer/Xploder/X-Terminator (FCD/Blaze)
+The FCD/Blaze devices are all same hardware-wise (with some cosmetic PCB
+revisions, and with extra SRAM and bigger FLASH installed in some carts). The
+DB25 connector can be directly connected to a PC parallel port.
+--> Cheat Devices - Xplorer Memory and I/O Map
+--> Cheat Devices - Xplorer DB25 Parallel Port Function Summary
+--> Cheat Devices - Xplorer DB25 Parallel Port Command Handler
+--> Cheat Devices - Xplorer DB25 Parallel Port Low Level Transfer Protocol
+--> Cheat Devices - Xplorer Versions
+--> Cheat Devices - Xplorer Chipset Pinouts
+--> Cheat Devices - Xplorer Cheat Code Format
+--> Cheat Devices - Xplorer Cheat Code and ROM-Image Decryption
+
+FLASH Chips (for both Xplorer and Datel)
+--> Cheat Devices - FLASH/EEPROMs
+
+http://gamehacking.org/faqs/hackv500c.html - cheat code formats
+http://doc.kodewerx.org/hacking_psx.html - cheat code formats
+http://xianaix.net/museum.htm - around 64 bios versions
+http://www.murraymoffatt.com/playstation-xplorer.html - xplorer bioses
+
+Separating between Gameshark and Xplorer Codes
+ First Digit Usage
+ 3,8 Same for Gameshark & Xplorer (for Xplorer: can be encrypted)
+ 1,2,C,D,E Gameshark
+ 4,6,7,9,B,F Xplorer
+ 0,5 Meaning differs for Gameshark & Xplorer
+ A Unused
+
+Codebreaker
+Megacom Power Replay III Game Enhancer
+
+Cheat Devices - Datel I/O
+-------------------------
+
+Datel Memory and I/O Map (for PAR2 or so)
+ 1F000000h-1F01FFFFh R/W Flash (first 128K)
+ 1F020010h R Comms Link STB pin state (bit0)
+ 1F020018h R Switch Setting (bit0: 0=Off, 1=On)
+ 1F040000h-1F05FFFFh R/W Flash (second 128K) + feedback area (see below)
+ 1F060000h R Comms Link data in (byte)
+ 1F060008h W Comms Link data out (byte, pulses ACK to Comms Link)
+
+Datel PAR1
+Original PAR1 might have supported only 128K FLASH (?) if so, the I/O ports are
+probably same as above, but without the "second 128K" FLASH area.
+
+Datel PAR3
+The PAR3 version is said to work with parallel ports (not needing the Comms
+Link ISA card), and said to support more FLASH with bankswitching, so the I/O
+ports must work somehow entirely different as described above.
+Some notes from a (poorly translated) japanese document:
+PAR3 Memory:
+ 1f000000-1f01ffff ROM. Change in bank switching.
+ 1f020000-1f03ffff ROM. Change in bank switching.
+ 1f040000-1f05ffff whopping RAM. It is able to use.
+ 1f060000-1f06003f I/O. Intently mirror to the subsequent 1f07ffff.
+PAR3 I/O:
+ 1f060000 for reception. (1f060000 use only.) All bytes same treatment like.
+ It is 01h in the state that does not connected anything.
+ 1f060008 for transmission. (1f060008 use only.) This is ffh in the state
+ that does not connected anything.
+ 1f060010 during data reception it will stand the least significant bit.
+ Usually is fe.
+ 1f060018 state of the push button. In not pressed and fefefefefefefefe,
+ it will Ost ffffffffffffffff.
+ 1f060020 I think 1f060020 unused. It is ffffffffffffffff.
+ 1f060028 I think 1f060028 unused. It is ffffffffffffffff.
+ 1f060030 bank switching. 1 put and run-time of the ROM, and changes to the
+ 3's and the start-up of the ROM.
+ 1f060038 would be what? It is lbu. Like there is a meaning bits 0 and 1.
+ It was fcfcfcfcfcfcfcfc. I think that it is bank cult.
+
+Cheat Devices - Datel DB25 Comms Link Protocol
+----------------------------------------------
+
+Boot Command Handler
+The Boot Command Handler is executed once at Pre-Boot, and also (at least in
+some firmware versions) once before displaying the GUI. Following command(s)
+can be sent from PC side:
+ Repeatedly send 8bit "W", until receiving "R"
+ Repeatedly send 8bit "B", until receiving "W"
+ Send 8bit command "X" (upload/exec) or "U" (upload/flash), and receive ECHO
+ Send 32bit ADDRESS, and receive ECHO or "BX" (bad command)
+ Send 32bit LENGTH, and receive ECHO
+ Send DATA[LENGTH], and receive ECHO
+ Send 16bit CHECKSUM, and receive ECHO
+ (for upload/flash and if checksum was good, PSX will now BURN ADDR,LENGTH)
+ Send 16bit DUMMY, and receive "OK"/"BC"/"BF" (okay, bad chksum, bad flash)
+ (for upload/exec and if checksum was good, PSX will now CALL ADDR)
+ (thereafter, PAR2.0 and up will reboot via jmp BFC00000h)
+Data is always transferred as byte-pair (send one byte, receive one byte),
+16bit/32bit values are transferred MSB first (with ECHO after each byte).
+The upload/exec command is supported by both Datel and Caetla, the upload/flash
+command is supported by Datel only (but it's totally bugged in PAR1.99, and
+might also have upwards compatiblity issues in later versions, so it's better
+to upload a custom flash function via upload/exec instead of using
+upload/flash).
+The 16bit checksum is all DATA[len] bytes added together, and then ANDed with
+0FFFh (ie. actually only 12bit wide).
+
+Menu/Game Command Handler
+There must be some further command handler(s) after the Boot Command Handler,
+with support for additional cheat related commands, and (at least in Caetla)
+with support for uploading EXE files with Kernel functions installed (the Boot
+Command Handler at Pre-Boot time can also upload EXE code, but doesn't have
+Kernel installed).
+Original Datel commands for Menu/Game mode are unknown. The Caetla commands are
+documented in japanese, and there are also two english translations:
+http://www.psxdev.net/forum/viewtopic.php?f=49&t=370 - good (though incomplete)
+http://www.psxdev.net/forum/viewtopic.php?f=53&t=462#p6849 - very bad (beware)
+
+Cheat Devices - Datel Chipset Pinouts
+-------------------------------------
+
+There appear to be numerous Datel hardware revisions (and possibly numerous
+Datel clones). So this chapter is unlikely to cover all hardware revisions.
+ PSX Expansion cards:
+ PCB Controller FLASH DB25 spotted by
+ DATEL REF 1215 GAL + 74HC245 128K+128K yes Type79
+ DATEL REF 1288 DATEL ASIC1 256K yes nocash
+ DATEL xxx? GAL + PIC + HC245 128K yes CharlesMacD
+ noname? GAL + 74HC245 256K+0K yes Type79
+ DATEL REF 1324 lots of chips? lots? no CyrusDevX
+ DATEL REF 1326 lots of chips? lots? yes Type79
+ PS-121 ZISAN GAL + PIC? + HC245 128K yes Kryptonick
+ JSZ-02 GAL (+HC245?) 128K (yes) nocash
+ Comms Link ISA cards:
+ PCB Chipset spotted by
+ DATEL COMMS LINK, XXX? blurry SMD chipset? lowres photo
+ DATEL REF 1113, IBM SATURN LINK 1x74HC74, 2x74HC373, 1xXXX? Type79
+ EMS, PCCOM 1x74HC74, 2x74HC373, 1xXXX? jokergameth
+ DIY Alternatives to Comms Link
+ FiveWire ;simple hardware mod for use with parallel ports, for SPP/EPP
+ FreeWing ;parallel port adaptor, lots of 74xxx TTL chips, for SPP/EPP
+ ExStand ;parallel port adaptor, lots of 74xxx TTL chips, for EPP
+ CommLinkUSB ;USB adaptor, Buy-and-Diy technology (adafruit/teensy based)
+
+DATEL REF1288 board (with DATEL ASIC1 chip)
+The ASIC1 chip is found in this hardware:
+ Label: "EQUALIZER, EVEN THE ODDS" (sticker on outside of case)
+ Case: "DATEL ENGLAND" (printed inside of case)
+ PCB: "DATEL REF1288 SONY SONYPSX2meg"
+ U: 44pin "DATEL, ASIC1, A8B1944A, 9832" ;custom logic chip
+ U: 32pin "SST, 29EE020, 150-4C-NH, 981918-D" ;256Kx8 EEPROM
+ U: 8pin "83BA, LM78L, 05ACM" ;5V voltage regulator
+ CN: 25pin DB25 connector (for Comms Link ISA card)
+ CN: 68pin PSX expansion port connector
+ SW: 3pin Switch
+The ASIC1 is basically same as the PAL/GAL on other boards, with the 74HC245
+transceiver intergrated; the ASIC1 is using a 44pin PLCC package, with pin1
+being upper-middle, and pin7 being upper-left. Pinouts are:
+ 7 D0 18 DB25.2.DATA0 29 D0 (same as pin7) 40 A3
+ 8 D1 19 DB25.3.DATA1 30 EERPROM./WE 41 A4
+ 9 D2 20 DB25.4.DATA2 31 /WR 42 /EXP
+ 10 GND 21 GND 32 GND 43 GND
+ 11 D3 22 DB25.5.DATA3 33 /RD 44 A17
+ 12 D4 23 DB25.6.DATA4 34 /MODE ("jumper") 1 A18
+ 13 D5 24 DB25.7.DATA5 35 VCC 2 GND
+ 14 VCC 25 VCC 36 DB25.11.ACK 3 VCC
+ 15 D6 26 DB25.8.DATA6 37 ? 4 EEPROM./OE
+ 16 VCC 27 DB25.9.DATA7 38 VCC 5 DB25.10.STB
+ 17 D7 28 EEPROM./CS 39 ? 6 SWITCH
+D0 is wired to both pin7 and pin29. The /MODE pin is NC (but could be GNDed via
+the two solder points in middle of the PCB). The SWITCH has 10K pullup (can can
+get GNDed depending on switch setting).
+
+Power Replay III Game Enhancer?
+ PCB: "JSZ-02"
+ U1 32pin AMD AM29F010 (128Kx8 FLASH)
+ U2 20pin PALCE, 16V8H-25JC/4, 0018BZ2 (sticker "(C)DEC95, H00028, 340Y3")
+ U3 20pin Optional 74xxx? (not installed)
+ J1 68pin PSX expansion port connector
+ J2 25pin Optional DB25 connector (not installed)
+ K1 3pin Switch
+ resistor/z-diode for 5.1V supply (or optionally 2x1N4148 for about 6V)
+
+PALCE20V8 Cuthbert Action Replay schematic (from hitmen webpage)
+ 1-NC 8-NC 15-NC 22-NC
+ 2-FBIN 9-CPU.A4 16-GNDed 23-FLASH./WE
+ 3-CPU.A17 10-CPU./EXP 17-DB25.pin10 (PAR.STB) 24-FBOUT
+ 4-CPU./WR 11-CPU.A3 18-FLASH./CS 25-FLASH./OE (and BUF.DIR)
+ 5-CPU./RD 12-CPU.A5 19-DB25.pin11 (PAR.ACK) 26-BUF./EN
+ 6-CPU.A18 13-SWITCH 20-CPU.D0 27-unused
+ 7-CPU.A20 14-GND 21-FLASH.A17 28-VCC
+
+Charles MacDonald Game Shark schematic
+ 1-FBIN 7-CPU.A4.NC? 13-GNDed 19-FLASH./WE
+ 2-PIC.RC1 8-CPU./EXP.NC? 14-PAR.STB 20-FBOUT
+ 3-CPU./WR 9-CPU.A3 15-PIC.RA0 21-BUF.DIR
+ 4-CPU./RD 10-CPU.A2 16-PAR.ACK 22-BUF./OE
+ 5-CPU.A18 11-SWITCH 17-CPU.D0 23-PIC.RC0
+ 6-CPU.A17 12-GND 18-FLASH./OE 24-VCC
+Uhm, schematic shows "PAR.ACK" instead of "BUF.DIR" as transceiver direction?
+The 24pin PAL in Charles schematic does actually seem to be a 28pin PLCC GAL in
+actual hardware (which has four NC pins, hence the 24pin notation in the
+schematic).
+The three PIC pins connect to a 28pin PIC16C55 microprocessor (unknown
+purpose). Most of the PIC pins are NC (apart from the above three signals, plus
+supply, plus OSC ... derived from some oscillator located "behind" the DB25
+connector?).
+
+Charles MacDonald Gold Finger schematic
+ 1-FBIN 6-CPU.A17 11-CPU.A2 16-FBOUT
+ 2-SWITCH 7-CPU.A4.NC? 12-PAR.ACK 17-CPU.A20
+ 3-CPU./WR 8-CPU./EXP.NC? 13-CPU.D0 18-PAR.STB
+ 4-CPU./RD 9-CPU.A3 14-FLASH./OE 19-BUF./OE
+ 5-CPU.A18 10-GND 15-FLASH./WE 20-VCC
+Note: This is a datel clone, without "BUF.DIR" signal (instead, the transceiver
+DIR pin is wired to "PAR.ACK"; it's probably functionally same as real datel
+hardware, assuming that "PAR.ACK" is only a short pulse during writing; then
+reading should be possible anytime else).
+
+Charles MacDonald Comms Link schematic
+PAL
+ 1-/STATUS 7-ISA.A6 13-JP2 19-NC
+ 2-ISA.A1 8-ISA.A7 14-ISA.A9 20-PCWR
+ 3-ISA.A2 9-ISA.A8 15-NC 21-/PCRD
+ 4-ISA.A3 10-ISA.AEN 16-ISA./IOW 22-NC
+ 5-ISA.A4 11-JP1 17-/IRQ 23-ISA./IOR
+ 6-ISA.A5 12-GND 18-ISA.D0 24-VCC
+The JP1/JP2 pins allow to select Port 300h,310h,320h,330h via two jumpers. The
+/IRQ pin could be forward to ISA./IRQ2..7 via six jumpers (but the feature is
+ununsed and the six jumpers aren't installed at all).
+
+DB25 Connector
+ Pin Parallel Port CommsLink (PC) cable PAR (PSX)
+ 1 /STB ----> "strobe" ----.---o-------------o-- -- NC
+ 2-9 DATA <-/----> DATA <-- | --o-------------o-------> DATA
+ 10 /ACK <---- "strobe" ----'---o-------------o-------> "strobe"
+ 11 BUSY <---- "ack" <-------o-------------o-------- "ack"
+ 12 PE <---- NC -- --o-------------o-- -- NC
+ 13 SLCT <---- NC -- --o-------------o-- -- NC
+ 14 /AUTOLF ----> NC -- --o-------------o--. .-- GNDed
+ 15 /ERROR <---- NC -- --o-------------o--. .-- GNDed
+ 16 /INIT ----> NC -- --o-------------o--. .-- GNDed
+ 17 /SELECT ----> GNDed --. .--o-------------o--. .-- GNDed
+ 18-25 GND ----- GND --'--'--o-------------o--'--'-- GND
+
+nocash FiveWire mod (for connecting datel expansion cart to parallel port)
+ disconnect DB25.pin14,15,16,17 from GND (may require to desolder the DB25)
+ repair any GND connections that were "routed through" above pins
+ wire DB25.pin1./STB to DB25.pin10./ACK
+ wire DB25.pin16./INIT to PSX.EXPANSION.pin2./RESET
+ wire DB25.pin15./ERROR to PSX.EXPANSION.pin28.A20
+ wire DB25.pin13.SLCT to PSX.EXPANSION.pin62.A21
+ wire DB25.pin12.PE to PSX.EXPANSION.pin29.A22
+
+Cheat Devices - Datel Cheat Code Format
+---------------------------------------
+
+PSX Gameshark Code Format
+ 30aaaaaa 00dd ;-8bit Write [aaaaaa]=dd
+ 80aaaaaa dddd ;-16bit Write [aaaaaa]=dddd
+Below for v2.2 and up only
+ D0aaaaaa dddd ;-16bit/Equal If dddd=[aaaaaa] then (exec next code)
+ D1aaaaaa dddd ;-16bit/NotEqual If dddd<>[aaaaaa] then (exec next code)
+ D2aaaaaa dddd ;-16bit/Less If dddd<[aaaaaa] then (exec next code)
+ D3aaaaaa dddd ;-16bit/Greater If dddd>[aaaaaa] then (exec next code)
+ E0aaaaaa 00dd ;-8bit/Equal If dd=[aaaaaa] then (exec next code)
+ E1aaaaaa 00dd ;-8bit/NotEqual If dd<>[aaaaaa] then (exec next code)
+ E2aaaaaa 00dd ;-8bit/Less If dd<[aaaaaa] then (exec next code)
+ E3aaaaaa 00dd ;-8bit/Greater If dd>[aaaaaa] then (exec next code)
+ 10aaaaaa dddd ;-16bit Increment [aaaaaa]=[aaaaaa]+dddd
+ 11aaaaaa dddd ;-16bit Decrement [aaaaaa]=[aaaaaa]-dddd
+ 20aaaaaa 00dd ;-8bit Increment [aaaaaa]=[aaaaaa]+dd
+ 21aaaaaa 00dd ;-8bit Decrement [aaaaaa]=[aaaaaa]-dd
+Below for v2.41 and up only
+ D4000000 dddd ;-Buttons/If If dddd=JoypadButtons then (exec next code)
+ D5000000 dddd ;-Buttons/On If dddd=JoypadButtons then (turn on all codes)
+ D6000000 dddd ;-Buttons/Off If dddd=JoypadButtons then (turn off all codes)
+ C0aaaaaa dddd ;-If/On If dddd=[aaaaaa] (turn on all codes)
+Below probably v2.41, too (though other doc claims for v2.2)
+ 5000nnbb dddd ;\Slide Code aka Patch Code aka Serial Repeater
+ aaaaaaaa ??ee ;/for i=0 to nn-1, [aaaaaaaa+(i*bb)]=dddd+(i*??ee), next i
+ 00000000 0000 ;-Dummy (do nothing?) needed between slides (CD version only)
+Below probably v2.41, too (though other doc claims for ALL versions)
+ C1000000 nnnn ;-Delays activation of codes by nnnn (4000-5000 = 20-30 sec)
+ C2ssssss nnnn ;\Copy ssss bytes from 80ssssss to 80tttttt
+ 80tttttt 0000 ;/
+Below from Caetla .341 release notes
+These are probably caetla-specific, not official Datel-codes. In fact, Caetla
+.341 itself might be an inofficial hacked version of Caetla .34 (?) so below
+might be totally inofficial stuff:
+ C3aaaaaa 0000 ;\Indirect 8bit Write [[aaaaaa]+bbbb]=dd
+ 9100bbbb 000000dd ;/
+ C3aaaaaa 0001 ;\Indirect 16bit Write [[aaaaaa]+bbbb]=dddd (Tomb Raider 2)
+ 9100bbbb 0000dddd ;/
+ C3aaaaaa 0002 ;\Indirect 32bit Write [[aaaaaa]+bbbb]=dddddddd
+ 9100bbbb dddddddd ;/
+ FFFFFFFF 0001 ;-Optional prefix for GameShark 2.2 codes(force non-caetla)
+ 12aaaaaa dddddddd ;-32bit Increment [aaaaaa]=[aaaaaa]+dddddddd
+ 22aaaaaa dddddddd ;-32bit Decrement [aaaaaa]=[aaaaaa]-dddddddd
+
+Notes
+A maximum of 30 increment/decrement codes can be used at a time.
+A maximum of 60 conditionals can be used at a time (this includes Cx codes).
+Increment/decrement codes should (must?) be used with conditionals.
+Unknown if greater/less conditionals are signed or unsigned.
+Unclear if greater/less compare dddd by [aaaaaa], or vice-versa.
+Unknown if 16bit codes do require memory alignment.
+
+Cheat Devices - Xplorer Memory and I/O Map
+------------------------------------------
+
+Xplorer Memory Map
+ 1F000000h-1F03FFFFh.RW First 256K of FLASH (fixed mapping)
+ 1F040000h-1F05FFFFh.RW Map-able: 2x128K FLASH or 4x128K SRAM (if any)
+ 1F060000h-1F060007h.xx I/O Ports
+ 1F060008h-1F06FFFFh Mirrors of I/O at 1F060000h..1F060007h
+ 1F070000h-1F07FFFFh Unused (open bus)
+FLASH can be 256Kbyte (normal), or 512Kbyte (in FX versions). When programming
+FLASH chips: Observe that the carts can be fitted with chips from different
+manufacturers, and, Xplorer carts can have either one or two 256K chips, or one
+512K chip.
+SRAM can be 0Kbyte (normal/none), or 128Kbyte (in FX versions). The PCB
+supports max 512K SRAM (but there aren't any carts having that much memory
+installed).
+
+Xplorer I/O Map
+ 1F005555h.W FLASH Cmd 1st/3rd byte ;\for first FLASH chip
+ 1F002AAAh.W FLASH Cmd 2nd byte ;/
+ 1F045555h.W FLASH Cmd 1st/3rd byte ;\for 2nd FLASH chip (if any)
+ 1F042AAAh.W FLASH Cmd 2nd byte ;/
+ 1F060000h.R I/O - Switch Setting (bit0: 0=Off, 1=On)
+ 1F060001h.R I/O - 8bit Data from PC (bit0-7)
+ 1F060001h.W I/O - 8bit Latch (Data to PC, and Memory Mapping)
+ 0 DB25.pin13.SLCT ;\
+ 1 DB25.pin12.PE ; used for data to PC
+ 2 DB25.pin11.BUSY ;/
+ 3 DB25.pin10./ACK ;-used for handshake to PC
+ 4 Memory Mapping (0=EEPROM, 1=SRAM)
+ 5 Memory Mapping (EEPROM A17 when A18=1)
+ 6 Memory Mapping (SRAM A17 or SRAM CE2)
+ 7 Memory Mapping (SRAM A18 or NC)
+ 1F060002h.R I/O - Handshake from PC (bit0) (DB25.pin17./SEL)
+ 1F060005h.W I/O - Unknown (used by Xplorer v4.52, set to 03h)
+ 1F060006h.R I/O - Unknown (used by Xplorer v4.52, bit0 used)
+ 1F060007h.R I/O - Unknown (used by Xplorer v4.52, bit0 used)
+
+Cheat Devices - Xplorer DB25 Parallel Port Function Summary
+-----------------------------------------------------------
+
+Xplorer Parallel Port Commands (from PC side)
+ GetByteByAddr32 Tx(5702h,Addr32), Rx(Data8)
+ OldMenuBuReadFile Tx(5703h), TxFilename, RxDataFFEEh
+ OldMenuBuDeleteFile Tx(5704h), TxFilename
+ OldMenuBuWriteFile Tx(5705h), TxFilename, TxFiledata
+ OldMenuBuGetFileHdr Tx(5706h), TxFilename, Rx(00h,00h), RxTurbo, Rx(02h)
+ OldMenuBuOpenEvents Tx(5707h)
+ SetCop0Breakpoint Tx(5708h,Addr32,Mask32,Ctrl32) ;Menu: Dummy?
+ OldMenuBuCopyFile Tx(5709h), TxFilename ;to other memcard
+ OldMenuBuFormat Tx(570Ah,Port8)
+ OldMenuBuGetStatus2x Tx(570Bh), Rx(Stat8,Stat8) ;\different in old/new
+ NewMenuBuGetStatus1x Tx(570Bh,Port8), Rx(Stat8) ;/
+ MenuGetSetFlag Tx(570Ch), Rx(Flag8) ;get old flg, then set flg=01h
+ NewMenuBuReadSector Tx(570Dh,Port8,Sector16), Rx(Data[80h])
+ NewMenuBuWriteSector Tx(570Eh,Port8,Sector16,Data[80h])
+ NewRawExecute Tx(570Fh,Addr32) ;call Addr
+ MidMenuBuggedExecJump Tx(5710h,ORra32,ORgp32,ORsp32,pc32) ;aka r31,r28,r29,pc
+ MidMenuSendComment Tx(5711h,Len8,AsciiMessage[Len])
+ NewMenuFillVram Tx(5712h,Xloc32,Yloc32,Xsiz32,Ysiz32,FillValue32)
+ NewGetVram Tx(5713h,Xloc32,Yloc32), Rx(Data[800h]) ;32x32pix
+ NewGetSetIrqMask Tx(5714h), Rx(OldMask16), Tx(NewMask16) ;Menu: Dummy
+ NewSetVram Tx(5715h,Xloc8,Yloc8,Data[800h]) ;X/Y=div32 ;32x32pix
+ NewMenuGetFlgAndOrVal Tx(5716h), Rx(00h, or 01h,Val32) ;\
+ NewMenuGetTwoValues Tx(5717h), Rx(Val32,Val32) ;
+ NewMenu... Tx(5718h), ... ;
+ NewMenuGet2kGarbage Tx(5719h,Dummy32), Rx(Garbage[800h]) ; whatever
+ NewMenuGetSomeValue Tx(571Ah), Rx(Val32) ;
+ NewMenu... Tx(571Bh,Data[4]) ;similar to 5763h ;
+ NewMenuNoLongerSupp. Tx(571Ch) ;probably WAS supported someday ;/
+ GameAddCheatCode Tx(5741h,Addr32,Data16), Rx(Index8)
+ MenuReBootKernel Tx(5742h) ;jumps to BFC00000h
+ GameDelCheatCode Tx(5744h,Index8)
+ GetMem Tx(5747h,Addr32,Len32), Rx(Data[Len]), TxRxChksum
+ Lock/Freeze Tx(574Ch)
+ OldMenuBuGetDirectory Tx(574Dh), RxTurbo
+ MenuTestDB25Handshake Tx(574Eh), ...
+ MenuOptimalGetMem Tx(574Fh,Addr32,Len32), RxFaster(Data[Len]), TxRxChksum
+ OldMenuGetWhatever Tx(5750h), RxDataFFEEh ;-whatever
+ Release/Unfreeze Tx(5752h)
+ SetMem Tx(5753h,Addr32,Len32,Data[Len]), TxRxChksum
+ TurboGetMem Tx(5754h,Addr32,Len32), RxFast(Data[Len]), TxRxChksum
+ MenuSetMemAndBurnFirm Tx(5755h,Addr32,Len32,Data[Len]), TxRxChksum ;burnFlash
+ GetStateGameOrMenu Tx(5757h), Rx(47h=Game, or 58h=Menu)
+ SetMemAndExecute Tx(5758h,Addr32,Len32,Data[Len]), TxRxChksum ;call Addr
+ NewMenu... Tx(5763h,Val32) ;similar to 571Bh ;-whatever
+ GetByteByAddr24 Tx(5767h,Addr24), Rx(Data8)
+ NewMenuBuggedExecJump Tx(577Ah,ORra32,ORgp32,ORsp32,pc32) ;formerly 5710h
+ NewMenuFlashAndReboot Tx(57C7h,Dest32,Len32,DataXorD3h[Len])
+Function names starting with "Game/Menu" and/or "New/Mid/Old" are working only
+in Game/Menu mode, or only in New/Old xplorer firmware versions (new commands
+exist in v4.52, old commands exist in v1.091, mid commands exist in v2.005, but
+neither in v1.091 nor v4.52, unknown when those new/mid/old commands have been
+added/removed exactly, in which specific versions).
+
+The only useful command is SetMemAndExecute, which works in ALL versions, and
+which can be used to do whatever one wants to do (unfortunately, most of the
+official & inoffical tools are relying on other weird commands, which are
+working only with specific xplorer firmware versions).
+
+Cheat Devices - Xplorer DB25 Parallel Port Command Handler
+----------------------------------------------------------
+
+The command handler is called once and then during booting, during xplorer GUI,
+and during Game execution.
+Each call to the command handler does allow to execute ONLY ONE command,
+however, the "Freeze" command can be used to force the xplorer to stay in the
+command handler, so one can send MORE commands, until leaving the command
+handler by sending the "Unfreeze" command.
+The command handling can vary depending on current boot phase (see below
+cautions on Pre-Boot, Mid-Boot, and In-Game phases).
+
+Pre-Boot Handler
+This is called shortly after the kernel has done some basic initialization, and
+after the xplorer has relocated its EEPROM content to RAM (which means it may
+called about a second after reset when using official PSX kernel and Xplorer
+Firmware).
+ OLD Explorer Firmware: Call command handler ONCE (in MENU mode)
+ NEW Explorer Firmware: Call command handler TWICE (in MENU mode)
+ if SWITCH=ON or [80000030h]="WHB." then
+ NEW Explorer Firmware: Call command handler ONCE AGAIN (in MENU mode)
+ Install Mid-Boot hook
+ endif
+Observe that the Kernel function vectors at A0h, B0h, and C0h aren't installed
+at this point. If you want to upload an EXE with Kernel vectors installed: send
+THREE dummy commands (eg. Unfreeze) to skip the above early command handling.
+On the other hand, the ReBootKernel command can be used if you WANT to upload
+something during Pre-Boot (the ReBootKernel command works only in MENU mode
+though, ie. during Xplorer GUI, but not during Game).
+
+Mid-Boot Handler (Xplorer GUI)
+The Xplorer GUI is called only if the Pre-Boot handler has installed it (eg. if
+the SWITCH was ON). The handler is called alongsides with joypad reading (which
+does NOT take place during the Xplorer intro, so there will be a long dead spot
+between Pre-Boot and Mid-Boot command handling).
+ Call command handler ONCE (in MENU mode) alongsides with each joypad read
+Observe that the GUI may have smashed various parts of the Kernel
+initialization, so you can upload EXE files, and can use Kernel functions, but
+the EXE won't get booted in same state as when booting from CDROM. The boot
+state can also vary dramatically depending on the Xplorer Firmware version.
+
+Post-Boot Handler (at start of CDROM booting)
+This is called when starting CDROM booting.
+ Install GAME mode hook for the B(17h) ReturnFromException() handler
+ OLD Explorer Firmware: Call command handler ONCE (still in MENU mode)
+ NEW Explorer Firmware: Call command handler ONCE (already in GAME mode)
+
+In-Game Handler (after CDROM booting) (...probably also DURING booting?)
+This is called via the hooked B(17h) ReturnFromException() handler.
+ if SWITCH=ON
+ Call command handler ONCE (in GAME mode) upon each B(17h)
+ And, process game cheat codes (if any) upon each B(17h)
+ endif
+Observe that GAME mode doesn't support all commands. And, above will work only
+if the game does use B(17h), eg. when using non-kernel exception handling, or
+if it has crashed, or disabled exceptions. Some internal kernel functions are
+using ReturnFromException() directly (without going through the indirect B(17h)
+function table entry; so the hook cannot trap such direct returns).
+
+Cheat Devices - Xplorer DB25 Parallel Port Low Level Transfer Protocol
+----------------------------------------------------------------------
+
+All 16bit/24bit/32bit parameters are transferred MSB first.
+
+Tx(Data) - transmit data byte(s)
+ Output 8bit data to DATA0-7 (DB25.pin2-9) ;-Send Data (D0-D7)
+ Output /SEL=HIGH (DB25.pin17) ;\Handshake High
+ Wait until /ACK=HIGH (DB25.pin10) ;/
+ Output /SEL=LOW (DB25.pin17) ;\Handshake Low
+ Wait until /ACK=LOW (DB25.pin10) ;/
+
+Rx(Data) - receive data byte(s)
+ Wait until /ACK=HIGH (DB25.pin10) ;\
+ Get 3bit from SLCT,PE,BUSY (DB25.pin13,12,11) ; 1st Part (D6,D7,HIGH)
+ Output /SEL=HIGH (DB25.pin17) ;/
+ Wait until /ACK=LOW (DB25.pin10) ;\
+ Get 3bit from SLCT,PE,BUSY (DB25.pin13,12,11) ; 2nd Part (D3,D4,D5)
+ Output /SEL=LOW (DB25.pin17) ;/
+ Wait until /ACK=HIGH (DB25.pin10) ;\
+ Get 3bit from SLCT,PE,BUSY (DB25.pin13,12,11) ; 3rd Part (D0,D1,D2)
+ Output /SEL=HIGH (DB25.pin17) ;/
+ Wait until /ACK=LOW (DB25.pin10) ;\4th Part (ver,LOW,LOW)
+ Get 3bit from SLCT,PE,BUSY (DB25.pin13,12,11) ; (ver=LOW for v1.091)
+ Output /SEL=LOW (DB25.pin17) ;/ (ver=HIGH for v4.52)
+ Wait until all 4bits LOW (DB25.pin13,12,11,10);-xlink95 fails if not
+
+RxFast(Data) for TurboGetMem - slightly faster than normal Rx(Data)
+First, for invoking the Turbo transfer:
+ Wait for BUSY=LOW (DB25.pin11)
+ Output DATA = 00h (DB25.pin2-9)
+ Wait for BUSY=HIGH (DB25.pin11)
+ Output DATA = ECh (DB25.pin2-9)
+Thereafter, receive the actual Data byte(s) as so:
+ Wait for /ACK transition (DB25.pin10) ;\
+ Get 3bit from SLCT,PE,BUSY (DB25.pin13,12,11) ; 1st Part (D6,D7,LOW)
+ Output DATA = 02h (DB25.pin2-9) ;/
+ Wait for /ACK transition (DB25.pin10) ;\
+ Get 3bit from SLCT,PE,BUSY (DB25.pin13,12,11) ; 2nd Part (D3,D4,D5)
+ Output DATA = 04h (DB25.pin2-9) ;/
+ Wait for /ACK transition (DB25.pin10) ;\
+ Get 3bit from SLCT,PE,BUSY (DB25.pin13,12,11) ; 3rd Part (D0,D1,D2)
+ Output DATA = 01h (DB25.pin2-9) ;/
+The /ACK transitions can be sensed by polling the parallel port IRQ flag on PC
+side.
+
+RxFaster(Data) for OptimalGetMem - much faster than normal Rx(Data)
+First, for invoking the Turbo transfer:
+ Output DATA = 00h ;<-- crap (DB25.pin2-9) ;-BUGGY, but REQUIRED
+Thereafter, receive the actual Data byte(s) as so:
+ Get 4bit from SLCT,PE,BUSY,/ACK (DB25.pin13,12,11,10);\1st Part (D4,D5,D6,D7)
+ Output DATA = 00h (DB25.pin2-9) ;/
+ Get 4bit from SLCT,PE,BUSY,/ACK (DB25.pin13,12,11,10);\2nd Part (D0,D1,D2,D3)
+ Output DATA = 01h (DB25.pin2-9) ;/
+BUG: The first received byte will be garbage with upper and lower 4bit both
+containing the lower 4bits (the bugged firmware does explicitely want DATA=00h
+before transfer, although DATA=00h is also 'confirming' that the upper 4bit can
+be 'safely' replaced by lower 4bit).
+
+TxRxChksum for SetMem/GetMem functions
+ Tx(chkMsb), Rx(chkMsb), Tx(chkLsb), Rx(chkLsb), Rx("OK" or "CF" or "BG")
+The 16bit checksum is all bytes in Data[Len] added together. The two final
+response bytes should be "OK"=Okay, or, if the transmitted chksum didn't match,
+either "CF"=ChecksumFail (for SetMem functions) or "BG"=BadGetChecksum (for
+GetMem functions). MenuSetMemAndBurnFirm is a special case with three response
+codes: "OF"=FlashOkay, "CF"=ChecksumFail, "FF"=FlashWriteFail.
+
+TxFilename for Memcard (bu) functions
+ Rx(Addr32), Tx(Addr32,Len32,Data[Len]), TxRxChksum
+This is internally using the standard "SetMem" function; preceeded by
+Rx(Addr32). Whereas Addr is the target address for the filename (just pass the
+Rx'ed address to the Tx part), Len should be max 38h, Data should be the
+filename with ending zero (eg. "bu10:name",00h).
+
+TxFiledata for Memcard (bu) WriteFile
+ Rx(Filename[26h]) ;-name from TxFilename, echo'ed back
+ Rx(Addr32) ;-buffer address for fragments
+ Tx(NumFragments8) ;-number of fragments
+ Tx(Addr32,Len32,Data[Len]), TxRxChksum ;<-- repeat this for each fragment
+ Rx(FileHandle8) ;-ending dummy byte (filehandle)
+This is also using the standard "SetMem" function, plus some obscure extra's.
+The filedata is split into fragments, Len should be max 2000h per fragment.
+
+RxDataFFEEh for Memcard (bu) ReadFile and GetWhatever
+ Rx(FFEEh,"W",Len32,Data[Len] ;<-- can be repeated for several fragments
+ Rx(FFEEh,"CA") ;<-- End Code (after last fragment)
+Memcard ReadFile does transfer N fragments of Len=2000h (depending on
+filesize). The GetWhatever function transfers one fragment with Len=80h,
+followed by N*6 fragments with Len=40Ah.
+
+RxTurbo for Memcard (bu) GetDirectory/GetFileHeader functions
+ Rx(Addr32), Tx(Addr32,Len32), RxFast(Data[Len]), TxRxChksum
+This is internally using the standard "TurboGetMem" function; preceeded by
+Rx(Addr32). Whereas Addr is the source address of the actual data (just pass
+the Rx'ed address to the Tx part).
+For GetDirectoy, Len should be max 800h (actual/data data is only 4B0h bytes,
+ie. 258h bytes per memcard, aka 28h bytes per directory entry). For
+GetFileHeader, Len should be max 80h.
+
+Cheat Devices - Xplorer Versions
+--------------------------------
+
+Xplorer names
+ Xploder (Germany/USA)
+ Xplorer (England/Spain/Netherlands)
+ X-Terminator (Japan)
+
+Xplorer suffices
+ V1/V2/V3 normal boards (256K EEPROM, no SRAM, no DB25 resistor)
+ FX/DX extended boards (512K EEPROM, 128K SRAM, with DB25 resistor)
+ PRO meaningless suffix
+The V1/V2/V3 suffix does just indicate the pre-installed firmware version (so
+that suffices become meaningless after software upgrades).
+The FX suffix (or DX in japan) indicates that the PCB contains more memory and
+an extra resistor (the memory/resistor are intended for use with the "X-Assist"
+add-on device).
+
+Xplorer PCB types
+ 1) PXT6 ;original board
+ 2) Nameless ;with alternate solder pads for smaller SRAM/GAL
+ 3) PXT6-3 ;with alternate solder pads for smaller SRAM/GAL and 2nd EEPROM
+
+Xplorer Compatibility Issues
+The three PCB versions are functionally identical, and do differ only by
+cosmetic changes for alternate/smaller chip packages.
+However, some things that can make difference in functionality are the
+installed components and installed firmware version:
+ - FX carts have some extra components & more memory installed.
+ (needed for "bigger" firmwares, mainly needed for the X-Assist add-on)
+ - FLASH chips from different manufacturers can occassionally cause problems
+ (eg. older software not knowing how to program newer FLASH chips).
+ - DB25 transfer protocol has some changed commands in each firmware version
+ (and most transfer tools tend to rely on such commands, so most tools will
+ fail unless the cart is flashed with a certain firmware version).
+
+X-Assist add-on for Xplorer carts
+The X-Assist is a quity huge clumsy controller with DPAD, plus 4 buttons, plus
+small LCD screen. The thing connects to the Xplorer's DB25 connector, allowing
+to enter/search cheat codes without using a PC.
+The device works only with "FX" Xplorer boards (which contain an extra resistor
+for outputting supply power on the DB25 connector, plus more memory which is
+somewhat intended for use by the X-Assist thing).
+
+Cheat Devices - Xplorer Chipset Pinouts
+---------------------------------------
+
+Xplorer Pinout GAL20V8 (generic array logic)
+ 1 IN0 (DB25.pin17./SEL)
+ 2 IN1 (PSX.pin14.A0)
+ 3 IN2 (PSX.pin48.A1)
+ 4 IN3 (PSX.pin15.A2)
+ 5 IN4 (74373.pin15.Q5)
+ 6 IN5 (PSX.pin4./EXP)
+ 7 IN6 (74373.pin12.Q4)
+ 8 IN7 (PSX.pin26.A16) (EEPROM.pin2.A16) (SRAM.pin2.A16) (10000h)
+ 9 IN8 (PSX.pin60.A17) (20000h)
+ 10 IN9 (PSX.pin27.A18) (EEPROM.pin1.A18 or NC) (40000h)
+ 11 IN10 (PSX.pin30./RD)
+ 12 GND
+ ---
+ 13 IN11 (GND)
+ 14 IN12 (/SWITCH_ON)
+ 15 IO (74373.pin11.LE)
+ 16 IO (PSX.pin6.D0)
+ 17 IO (SRAM./CE.pin22)
+ 18 IO (EEPROM2./CE.pin22) (for 2nd EEPROM chip, if any)
+ 19 IO (EEPROM1./CE.pin22) (for 1st EEPROM chip)
+ 20 IO (NC) (reportedly has wire?)
+ 21 IO (EEPROM.pin30.A17) (reportedly A14 ?)
+ 22 IO (74245.pin19./E)
+ 23 IN13 (PSX.pin64./WR) (SRAM.29, EEPROM.31)
+ 24 VCC
+The GALs are programmed nearly identical for all Xplorer versions, some small
+differences are: One or two EEPROM chip selects (depending on EEPROM chipset),
+and extra ports at 1F060005h, 1F060006h, 1F060007h (used in v4.52).
+Note: The 28pin PLCC GAL has same pinout as the 24pin chip, but with four NC
+pins inserted (at pin 1,8,15,22, whereof, there is a wire routed "through" pin
+8, so that pin isn't literally NC).
+
+Xplorer Pinout 74373 (8bit tristate latch)
+ 1 /OE (GND)
+ 2 Q0 (DB25.pin13.SLCT)
+ 3 D0 (PSX)
+ 4 D1 (PSX)
+ 5 Q1 (DB25.pin12.PE)
+ 6 Q2 (DB25.pin11.BUSY)
+ 7 D2 (PSX)
+ 8 D3 (PSX)
+ 9 Q3 (DB25.pin10./ACK)
+ 10 GND
+ 11 LE (GAL.pin15.LatchEnable)
+ 12 Q4 (GAL.pin7) (0=EEPROM, 1=SRAM)
+ 13 D4 (PSX)
+ 14 D5 (PSX)
+ 15 Q5 (GAL.pin5) (EEPROM bank 2/3)
+ 16 Q6 (SRAM.pin30.A17 or CE2)
+ 17 D6 (PSX)
+ 18 D7 (PSX)
+ 19 Q7 (SRAM.pin1.A18 or NC)
+ 20 VCC
+
+Xplorer Pinout 74245 (8bit bus transceiver)
+ 1 DIR (GNDed)
+ 2 D7 (PSX)
+ 3 D6 (PSX)
+ 4 D5 (PSX)
+ 5 D4 (PSX)
+ 6 D3 (PSX)
+ 7 D2 (PSX)
+ 8 D1 (PSX)
+ 9 D0 (PSX)
+ 10 GND
+ 11 D0 (DB25.pin2)
+ 12 D1 (DB25.pin3)
+ 13 D2 (DB25.pin4)
+ 14 D3 (DB25.pin5)
+ 15 D4 (DB25.pin6)
+ 16 D5 (DB25.pin7)
+ 17 D6 (DB25.pin8)
+ 18 D7 (DB25.pin9)
+ 19 /E (GAL.pin22)
+ 20 VCC
+
+Xplorer Pinout 7805 (voltage regulator)
+ 1 5V (VCC)
+ 2 GND (GND)
+ 3 7.5V (PSX.pin18,52)
+
+Xplorer Pinout SWITCH (on/off)
+ OFF NC
+ COM PAL.pin14 (with 10K pull-up to VCC)
+ ON GND
+
+Xplorer Pinout DB25 (parallel/printer port)
+ 1 In /STB (NC)
+ 2 In DATA0 (74245.pin11)
+ 3 In DATA1 (74245.pin12)
+ 4 In DATA2 (74245.pin13)
+ 5 In DATA3 (74245.pin14)
+ 6 In DATA4 (74245.pin15)
+ 7 In DATA5 (74245.pin16)
+ 8 In DATA6 (74245.pin17)
+ 9 In DATA7 (74245.pin18)
+ 10 Out /ACK (74373.Q3)
+ 11 Out BUSY (74373.Q2)
+ 12 Out PE (74373.Q1)
+ 13 Out SLCT (74373.Q0)
+ ---
+ 14 In /LF (NC)
+ 15 Out /ERR (VCC via 0.47ohm) (installed only on carts with SRAM)
+ 16 In /INIT (NC)
+ 17 In /SEL (GAL.IN0.pin1)
+ 18..25 GND (Ground)
+
+EEPROM.pin1 is NC on 256Kx8 chip (however it is wired to A18 for use with
+512Kx8 chips).
+EEPROM.pin30 is A17 from GAL.pin21 (not from PSX.A17), accordingly GAL.pin21 is
+EEPROM.A17 (not A14).
+Boards with solder pads for TWO EEPROMs are leaving A18 not connected on the
+2nd EEPROM (but do connect A18 to the first EEPROM, so one could either use one
+512K chip or two 256K chips).
+DB25.pin15./ERR is VCC via 0.47ohm (installed only on carts with SRAM, intended
+as supply for the X-ASSIST thing).
+SRAM (if any) is wired to GAL.pin17 (/CE), 74373.Q6 (A17 or CE2), 74373.Q7 (A18
+or NC), other SRAM pins are wired straight to D0-D7, A0-A16, /RD, /WR.
+VCC is 5V, derived from a 7805 voltage converter (with 7.5V used as input).
+Existing boards seem to have 128K SRAM (if any), so SRAM A17/A18 aren't
+actually used (unless a board would have 512K SRAM), however, for 128K SRAMs
+one should switch SRAM CE2 (aka A17) high.
+
+Cheat Devices - Xplorer Cheat Code Format
+-----------------------------------------
+
+PSX Xplorer/Xploder Code Format
+ 3taaaaaa 00dd ;-8bit write [aaaaaa]=dd
+ 8taaaaaa dddd ;-16bit write [aaaaaa]=dddd
+ 00aaaaaa dddd ;-32bit write [aaaaaa]=0000dddd <-- not "0taaaaaa dddd" ?
+ 4t000000 000x ;-Slow Motion (delay "x" whatever/ns,us,ms,frames?)
+ 7taaaaaa dddd ;-IF [aaaaaa]=dddd then <execute following code>
+ 9taaaaaa dddd ;-IF [aaaaaa]<>dddd then <execute following code>
+ Ftaaaaaa dddd ;-IF [aaaaaa]=dddd then activate "other selected" codes (uh?)
+ 5taaaaaa ?nnn ;\
+ d0d1d2d3 d4d5 ; write "?nnn" bytes to [aaaaaa] ;ordered d0,d1,d2... ?
+ d6d7d8.. .... ;/
+ 6t000000 nnnn ;\COP0 hardware breakpoint
+ aaaaaaaa cccc ; aaaaaaaa=break_address, mmmmmmmm=break_mask
+ mmmmmmmm d0d1 ; nnnn=num_bytes (d0,d1,d2,etc.), cccc=break_type (see below)
+ d2d3d4.. .... ;/
+ B?nnbbbb eeee ;\Slide/Patch Code, with unclear end: "end=?nn+/-1" ?
+ 10aaaaaa dddd ;/for i=0 to end, [aaaaaa+(i*bbbb)]=dddd+(i*eeee), next i
+ C0aaaaaa dddd ;-garbage/mirror of 70aaaaaa dddd ? ;\or maybe meant to be
+ D0aaaaaa dddd ;-garbage/mirror of 70aaaaaa dddd ? ;/same as on GameShark?
+The second code digit (t) contains encryption type (bit0-2), and a "default
+on/off" flag (bit3: 0=on, 1=off; whatever that means, it does probably require
+WHATEVER actions to enable codes that are "off"; maybe via the Ftaaaaaa dddd
+code).
+
+break_type (cccc) (aka MSBs of cop0r7 DCIC register)
+ E180 (instruction gotton by CPU but not yet implemented) (uh, gotton what?)
+ EE80 (data to be read or written) ;<--looks okay
+ E680 (data to be read) ;<--looks okay
+ EA80 (data to be wrtten) ;<--looks okay
+ EF80 (instruction) ;<-- looks crap, should be probably E180
+The CPU supports one data breakpoint and one instruction breakpoint (though
+unknown if the Xplorer does support to use both simultaneously, or if it does
+allow only one of them to be used).
+If the break_type/address/mask to match up with CPU's memory access actions...
+then "something" does probably happen (maybe executing a sub-function that
+consists of the d0,d1,d2,etc-bytes, if so, maybe at a fixed/unknown memory
+address, or maybe at some random address; which would require relocatable
+code).
+
+Notes
+The "Slide" code shall be used only with even addresses, unknown if other
+16bit/32bit codes do also require aligned addresses.
+
+Cheat Devices - Xplorer Cheat Code and ROM-Image Decryption
+-----------------------------------------------------------
+
+decrypt_xplorer_cheat_code:
+ key = x[0] and 07h ;'''''''' AABBCCDD EEFF '''''''';
+ x[0] = x[0] xor key ; / / / \ \ \ ;
+ if key=0 ; x[0] --' / / \ \ '-- x[5] ;
+ ;unencrypted (keep as is) ; x[1] ---' / \ '--- x[4] ;
+ elseif key=4 ; x[2] ----' '----- x[3] ;
+ x[1] = x[1] xor (025h) ;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;
+ x[2] = x[2] xor (0FAh + (x[1] and 11h))
+ x[3] = x[3] xor (0C0h + (x[2] and 11h) + (x[1] xor 12h))
+ x[4] = x[4] xor (07Eh + (x[3] and 11h) + (x[2] xor 12h) + x[1])
+ x[5] = x[5] xor (026h + (x[4] and 11h) + (x[3] xor 12h) + x[2] + x[1])
+ elseif key=5
+ x[1] = (x[1] + 057h) ;"W"ayne
+ x[2] = (x[2] + 042h) ;"B"eckett
+ x[3] = (x[3] + 031h) ;"1"
+ x[4] = (x[4] + 032h) ;"2"
+ x[5] = (x[5] + 033h) ;"3"
+ elseif key=6
+ x[1] = (x[1] + 0ABh) xor 01h
+ x[2] = (x[2] + 0ABh) xor 02h
+ x[3] = (x[3] + 0ABh) xor 03h
+ x[4] = (x[4] + 0ABh) xor 04h
+ x[5] = (x[5] + 0ABh) xor 05h
+ elseif key=7
+ x[5] = x[5] + 0CBh
+ x[4] = x[4] + 0CBh + (x[5] and 73h)
+ x[3] = x[3] + 05Ah + (x[4] and 73h) - (x[5] xor 90h)
+ x[2] = x[2] + 016h + (x[3] and 73h) - (x[4] xor 90h) + x[5]
+ x[1] = x[1] + 0F5h + (x[2] and 73h) - (x[3] xor 90h) + x[4] + x[5]
+ else
+ error ;(key=1,2,3)
+ endif
+
+decrypt_xplorer_fcd_rom_image:
+ for i=0 to romsize-1
+ x=45h
+ y=(i and 37h) xor 2Ch
+ if (i and 001h)=001h then x=x xor 01h
+ if (i and 002h)=002h then x=x xor 01h
+ if (i and 004h)=004h then x=x xor 06h
+ if (i and 008h)=008h then x=x xor 04h
+ if (i and 010h)=010h then x=x xor 18h
+ if (i and 020h)=020h then x=x xor 30h
+ if (i and 040h)=040h then x=x xor 60h
+ if (i and 080h)=080h then x=x xor 40h
+ if (i and 100h)=100h then x=x xor 80h
+ if (i and 006h)=006h then x=x xor 0ch
+ if (i and 00Eh)=00Eh then x=x xor 08h
+ if (i and 01Fh)>=016h then x=x-10h
+ rom[i]=(rom[i] XOR x)+y
+ next i
+
+Cheat Devices - FLASH/EEPROMs
+-----------------------------
+
+FLASH/EEPROM Commands
+Below commands should work on all chips (for write: page size may vary, eg. 1
+byte, 128 bytes, or 256 bytes). Some chips do have some extra commands (eg. an
+alternate older get id command, or sector erase commands, or config commands),
+but those extras aren't needed for basic erase/write operations.
+ [5555h]=AAh, [2AAAh]=55h, [5555h]=A0h, [addr..]=byte(s) ;write page
+ [5555h]=AAh, [2AAAh]=55h, [5555h]=90h, id=[0000h..0001h] ;enter id mode
+ [5555h]=AAh, [2AAAh]=55h, [5555h]=F0h ;exit id mode
+ [5555h]=AAh, [2AAAh]=55h, [5555h]=80h ;erase chip, step 1
+ [5555h]=AAh, [2AAAh]=55h, [5555h]=10h ;erase chip, step 2
+Above addresses are meant to be relative to the chip's base address (ie.
+"5555h" would be 1F005555h in PSX expansion ROM area, or, if there are two
+flash chips, then it would be 1F045555h for the 2nd chip in xplorer and datel
+carts; whereas, that region is using bank switching in xplorer carts, so one
+must output some FLASH address bits I/O ports, and the others via normal CPU
+address bus; whilst datel carts have noncontinous FLASH areas at 1F000000h and
+1F040000h, with a gap at 1F020000h).
+Observe that the chips will output status info (instead of FLASH data) during
+write/erase/id mode (so program code using those commands must execute in RAM,
+not in FLASH memory).
+
+FLASH/EEPROM Wait Busy
+Waiting is required after chip erase and page write (after writing the last
+byte at page end), and on some chips it's also required after enter/exit id
+mode. Some chips indicate busy state via a toggle bit (bit6 getting inverted on
+each 2nd read), and/or by outputting a value different than the written data,
+and/or do require hardcoded delays (eg. AM29F040). Using the following 3-step
+wait mechanism should work with all chips:
+ Wait 10us (around 340 cpu cycles on PSX) ;-step 1, hardcoded delay
+ Wait until [addr]=[addr] ;-step 2, check toggle bit
+ Wait until [addr]=data ;-step 3, check data
+Whereas, "addr" should be the last written address (or 0000h for erase and
+enter/exit id mode). And "data" should be the last written data (or FFh for
+erase, or "don't care" for enter/exit id mode).
+
+Board and Chip Detection
+First of, one should detect the expansion board type, this can be done as so:
+ Enter Chip ID mode (at 1F000000h)
+ Compare 400h bytes at 1F000000h vs 1F020000h
+ If different --> assume Datel PAR1/PAR2 hardware
+ If same --> assume Xplorer hardware (or Datel PAR3, whatever that is)
+ Exit Chip ID mode (at 1F000000h)
+Next, detect the Chip ID for the (first) FLASH chip:
+ Enter Chip ID mode (at 1F000000h)
+ Read the two ID bytes (at 1F00000xh)
+ Exit Chip ID mode (at 1F000000h)
+Finally, one needs to check if there's a second FLASH chip, there are two such
+cases:
+ If cart=xplorer AND 1st_chip=256K --> might have a 2nd 256K chip
+ If cart=datel AND 1st_chip=128K --> might have a 2nd 128K chip
+In both cases, the 2nd chip would be mapped at 1F400000h, and one can test the
+following four combinations:
+ Enter Chip ID (at 1F000000h) and Enter Chip ID (at 1F400000h) ;id1+id2
+ Exit Chip ID (at 1F000000h) and Enter Chip ID (at 1F400000h) ;id2
+ Exit Chip ID (at 1F400000h) and Enter Chip ID (at 1F000000h) ;id1
+ Exit Chip ID (at 1F400000h) and Exit Chip ID (at 1F000000h) ;none
+For each combination compare 400h bytes at 1F000000h vs 1F400000h.
+ If they are all same --> there is only one chip (mirrored to both areas)
+ If different --> 1F400000h is either garbage, or a 2nd chip
+In the latter case, do Chip ID detection at 1F400000h to see if there's really
+another chip there, and which type it is (if present, then it should be usually
+the same type as the 1st chip; and if it's not present, then there might be
+just open bus garbage instead of valid ID values).
+
+FLASH/EEPROM Chip IDs
+ ChipID Kbyte Page Maker/Name ;notes
+ 1Fh,D5h 128K 128 ATMEL AT29C010A ;xplorer/prototypes?
+ 1Fh,35h 128K 128 ATMEL AT29LV010A ;-
+ 1Fh,DAh 256K 256 ATMEL AT29C020 ;xplorer
+ 1Fh,BAh 256K 256 ATMEL AT29BV020 ;xplorer
+ 1Fh,A4h 512K 256 ATMEL AT29C040A ;xplorer
+ 1Fh,C4h 512K 256 ATMEL AT29xV040A ;-
+ BFh,07h 128K 128 SST SST29EE010 ;-
+ BFh,08h 128K 128 SST SST29xE010 ;-
+ BFh,22h 128K 128 SST SST29EE010A ;-
+ BFh,23h 128K 128 SST SST29xE010A ;-
+ BFh,10h 256K 128 SST SST29EE020 ;xplorer & datel
+ BFh,12h 256K 128 SST SST29xE020 ;xplorer
+ BFh,24h 256K 128 SST SST29EE020A ;-
+ BFh,25h 256K 128 SST SST2xEE020A ;-
+ BFh,04h 512K 256 SST SST28SF040 ;said to be used in "AR/GS Pro"
+ DAh,C1h 128K 128 WINBOND W29EE01x ;-
+ DAh,45h 256K 128 WINBOND W29C020 ;-
+ DAh,46h 512K 256 WINBOND W29C040 ;xplorer
+ 01h,20h 128K 1 AMD AM29F010 ;pcb "JSZ-02" (power replay iii)
+ 01h,A4h 512K 1 AMD AM29F040 ;nocash psone bios (intact console)
+ 20h,20h 128K 1 ST M29F010B ;nocash psone bios (broken console)
+ 31h,B4h 128K ?? CATALYST CAT28F010 ;NEEDS VPP=12V !!! ("PS-121 ZISAN")
+The above Atmel/SST/Winbond chips are commonly used in Datel or Xplorer carts
+(or both). The CATALYST chip is used in some Datel clones (but seems to require
+12 volts, meaning that it can't be properly programmed on PSX, nethertheless,
+it's reportedly working "well enough" to encounter flash corruption upon
+programming attempts). The two ST/AMD chips aren't really common in PSX world
+(except that I've personally used them in my PSones).
+
+PSX Dev-Board Chipsets
+----------------------
+
+Sony DTL-H2000 CPU Board
+ CL825 20pin pin test points (2x10 pins)
+ CL827 20pin pin test points (2x10 pins)
+ U83 64pin SEC KM4216V256G-60 (DRAM 256Kx16) ;dual-ported VRAM
+ U84 64pin SEC KM4216V256G-60 (DRAM 256Kx16) ;dual-ported VRAM
+ CL828 20pin pin test points (2x10 pins)
+ CL826 20pin pin test points (2x10 pins)
+ X10 4pin JC53.20 (PAL, 53.203425MHz)
+ X2 4pin 53.69317MHz (NTSC, 53.693175MHz)
+ U62 20pin LVT244 (dual 4-bit 3-state noninverting buffer/line driver)
+ U27 64pin Sony CXD2923AR ;GPU'b
+ CL813 20pin pin test points (2x10 pins)
+ CL814 20pin pin test points (2x10 pins) (with one resistor or so installed)
+ U16 160pin Sony CXD8514Q ;GPU'a
+ X7 4pin 67.73760 MHz
+ CL807 20pin pin test points (2x10 pins)
+ CL809 20pin pin test points (2x10 pins)
+ CL811 20pin pin test points (2x10 pins)
+ U801 208pin Sony CXD8530BQ ;CPU
+ U11 28pin SEC KM48V2104AJ-6 (DRAM 2Mx8) ;Main RAM
+ U10 28pin SEC KM48V2104AJ-6 (DRAM 2Mx8) ;Main RAM
+ U9 28pin SEC KM48V2104AJ-6 (DRAM 2Mx8) ;Main RAM
+ U8 28pin SEC KM48V2104AJ-6 (DRAM 2Mx8) ;Main RAM
+ CN801 100pin Blue connector (to other ISA board)
+ U66 48pin LVT16244? (quad 4-bit 3-state noninverting buffer/line driver)
+ U65 48pin LVT16244? (quad 4-bit 3-state noninverting buffer/line driver)
+ U64 48pin LVT16245? (dual 8-bit 3-state noninverting bus transceiver)
+ U34 100pin Sony CXD2922Q ;SPU
+ U63 14pin 74F74N (dual flipflop)
+ U32 44pin SEC KM416V256B1-8 (DRAM 256Kx16) ;SoundRAM
+ CL801 20pin pin test points (2x10 pins)
+ CL802 20pin pin test points (2x10 pins)
+ Q881 3pin voltage stuff?
+ U31 20pin 74ACT244P (dual 4-bit 3-state noninverting buffer/line driver)
+ U35 18pin Sony CXD2554P or OKI M6538-01 (aka MSM6538-01?) (audio related?)
+ U36 20pin Sanyo LC78815 ;16bit D/A Converter
+ U37 8pin NEC ...? C4558C? D426N0B or 9426HOB or so?
+ J806 8pin solder pads...
+ J805 9pin solder pads...
+ J804 10pin solder pads... (11pins, with only 10 contacts?)
+ - 48pin solder pads (12x4pin config jumpers or so)
+ U26 20pin SN74ALSxxx logic?
+ U71 24pin Sony CXA1xxxx? ;RGB?
+ JPxx 9pin PAL/NTSC Jumpers (three 3pin jumpers)
+ J801 24pin solder pads...
+ J803 9pin rear connector: Serial Port (3.3V) (aka "J308") (DB9) (5+4pin)
+ J802 15pin rear connector: AV Multi-out (5+5+5pin)
+ CN881 98pin ISA Bus Cart-edge (2x31 basic pins, plus 2x18 extended pins)
+
+Sony DTL-H2000 PIO Board
+ JP72x 68pin Black connector (maybe equivalent to 68pin PSX expansion port?)
+ SWI 5pin solder pads...
+ U371 40pin HN27C4000G-12 (512Kx8 / 256Kx16 EPROM) (sticker: "94/7/27")
+ U370 84pin Altera EPM7160ELC84-12 (sticker: "U730, cntl 1")
+ U3 14pin SN74ALS1004N (hex inverters)
+ U43 44pin Altera EPM7032LC44-10 (sticker: "U43, add 1")
+ U716 28pin Sharp LH5498D-35 (FIFO 2Kx9)
+ U717 28pin Sharp LH5498D-35 (FIFO 2Kx9)
+ U719 28pin Sharp LH5498D-35 (FIFO 2Kx9)
+ U720 28pin Sharp LH5498D-35 (FIFO 2Kx9)
+ U724 20pin SN74ALS688N (8bit inverting identity comparator with enable)
+ U722 20pin SN74ALS245AN (8bit tristate noninverting bus transceiver)
+ U47 20pin 74FCT244ATP (dual 4-bit 3-state noninverting buffer/line driver)
+ U732 48pin LVT16245? (dual 8-bit 3-state noninverting bus transceiver)
+ U711 20pin SN74ALS244BN (dual 4-bit 3-state noninverting buffer/line driver)
+ U712 20pin SN74ALS244BN (dual 4-bit 3-state noninverting buffer/line driver)
+ U713 20pin 74HC244AP (dual 4-bit 3-state noninverting buffer/line driver)
+ U714 20pin 74HC244AP (dual 4-bit 3-state noninverting buffer/line driver)
+ U721 20pin SN74ALS244BN (dual 4-bit 3-state noninverting buffer/line driver)
+ U55 14pin SN74ALS08N (quad 2-input AND gates)
+ U726 20pin SN74ALS245AN (8bit tristate noninverting bus transceiver)
+ U715 20pin 74HC244AP (dual 4-bit 3-state noninverting buffer/line driver)
+ JPxx 100pin Blue connector (to other ISA board)
+ U738 20pin LVT244 (SMD) (dual 4-bit 3-state noninverting buffer/line driver)
+ U734 32pin KM684000G-7 (SRAM 512Kx8) ;\maybe 1Mbyte EXP3 RAM ?
+ U733 32pin KM684000G-7 (SRAM 512Kx8) ;/
+ U725 20pin SN74ALS688N (8bit inverting identity comparator with enable)
+ S700 24pin 12bit DIP switch (select I/O Address bits A15..A4)
+ JP700 8pin Jumper (4x2 pins) (select IRQ15/IRQ12/IRQ11/IRQ10)
+ JP7xx 12pin Jumper (3x4 pins) (select DMA7/DMA6/DMA5)
+ U64 48pin LVT16245? (dual 8-bit 3-state noninverting bus transceiver)
+ U65 48pin LVT16244? (quad 4-bit 3-state noninverting buffer/line driver)
+ U66 48pin LVT16244? (quad 4-bit 3-state noninverting buffer/line driver)
+ U737 48pin LVT16244? (quad 4-bit 3-state noninverting buffer/line driver)
+ U710 20pin SN74ALS244BN (dual 4-bit 3-state noninverting buffer/line driver)
+ U709 20pin HD74HC245P (8bit tristate noninverting bus transceiver)
+ U723 14pin SN74ALS38AN (quad open-collector NAND gates with buffered output)
+ U2 14pin SN74LS19AN (hex inverters with schmitt-trigger)
+ U1 8pin Dallas DS1232 (MicroMonitor Chip) ;power-good-detect ?
+ U708 20pin HD74HC245P (8bit tristate noninverting bus transceiver)
+ X3 2pin 4.1900 (4.19MHz for SPC700 CPU)
+ U42 80pin P823, U01Q (Sony CXP82300 SPC700 CPU with piggyback EPROM socket)
+ U42' 32pin 27C256A-15 (EPROM 32Kx8) (sticker: "94/11/28")
+ U706 10pin some slim chip with 1x10 pins
+ BT700 2pin battery (or super-cap?) for DS1302S (?) (not installed)
+ U729? 5pin voltage stuff?
+ U40 8pin Dallas DS1302S (real time clock)
+ X4 2pin small crystal (32.768kHz for DS1302S)
+ JP702 34pin Black connector (maybe for internal CDROM Emulator ISA cart?)
+ U736 28pin Sony CXK58257ASP-70L (SRAM 32Kx8) ;CDROM Sector Buffer?
+ U735 100pin Sony CXD1199BQ ;CDROM Decoder/FIFO
+ JP715 40pin Blue connector... to external DTL-H2010 CDROM drive?
+ JP721 9pin rear connector: Joypad/Memcard 2 (DB9)
+ JP719 9pin rear connector: Joypad/Memcard 1 (DB9)
+ ? - rear hole for cdrom-cable to Blue 40pin connector?
+ J70x 98pin ISA Bus Cart-edge (2x31 basic pins, plus 2x18 extended pins)
+JP715 must be either connected to an external CDROM drive, or to some of
+"terminator" plug (which shortcuts Pin23 and Pin26 with each other; software
+may hang upon certain I/O operations without that terminator).
+
+Sony DTL-H2500 Dev board (PCI bus)
+Newer revision of the DTL-H2000 board. Consists of a single PCI card (plus tiny
+daughterboard with Controller ports).
+ Mainboard "PI-27 1-589-867-11, DTL-H2500, MAIN BOARD 1575E01A0, SONY"
+ Daughterboard "SONY,CN-102 1-589-865-11,CONNECTOR BOARD,DTL-H2500,1575E02A0"
+ CJ1 9pin rear connector: DB9
+ CJ2? 15pin rear connector: AV Multi-out (5+5+5pin)
+ CJ3 10pin gray connector (to controller daughterboard with two DB9's)
+ CJ4 34pin black connector (maybe for internal CDROM Emulator ISA cart?)
+ CJ5 50pin black connector (to DTL-H2510, Gray Internal CDROM Drive?)
+ CJ6 68pin black connector (maybe equivalent to 68pin PSX expansion port?)
+ - 124pin PCI bus cart edge connector
+ CJ1' 9pin rear connector: DB9 (CTR1, joypad 1) ;\
+ CJ2' 9pin rear connector: DB9 (CTR2, joypad 2) ; on daughterboard
+ CJ3' 10pin gray ribbon cable (to CJ3 on main board) ;/
+ IC103 208pin Sony CXD8530CQ (CPU)
+ IC106 28pin SEC KM48V2104AT-6 (DRAM 2Mx8)
+ IC107 28pin SEC KM48V2104AT-6 (DRAM 2Mx8)
+ IC108 28pin SEC KM48V2104AT-6 (DRAM 2Mx8)
+ IC109 28pin SEC KM48V2104AT-6 (DRAM 2Mx8)
+ IC201 64pin SEC KM4216V256G-60 (DRAM 256Kx16) ;dual-ported VRAM
+ IC202 64pin SEC KM4216V256G-60 (DRAM 256Kx16) ;dual-ported VRAM
+ IC203 160pin Sony CXD8514Q ;GPU'a
+ IC207 64pin Sony CXD2923AR ;GPU'b
+ IC303 28pin HM62W256LFP-7T (CDROM SRAM 32Kx8) ;on back side
+ IC304 52pin "D 2021, SC430920PB, G64C 185, JSAA9618A" (Sub-CPU) ;on back
+ IC305 100pin Sony CXD1199BQ (CDROM Decoder/FIFO) ;on back side
+ IC308 100pin Sony CXD2922BQ (SPU) ;on back side
+ IC310 44pin SEC KM416V256BLT-7 (DRAM 256Kx16) ;SoundRAM ;on back side
+ IC402 24pin something bigger
+ IC404 8pin something small
+ IC405 8pin something small
+ IC501 24pin Sony CXA1645M (Analog RGB to Composite) ;on back side
+ IC701 4pin "RD, 5B" or so ;on back side
+ IC801 +++pin "ALTERA, FLEX, EPF8820ARC208-3, A9607"
+ IC802 20pin LVT245A <-- ;on back side
+ IC803 52pin "IDT71321, LA35J, S9704P" (2Kx8 dual port SRAM)
+ IC804 20pin LVT244A
+ IC805 8pin something with socket (sticker: "PD3")
+ IC807-2 32pin MX 27C1000MC-90 (PROM) ;\on back side
+ IC808 32pin F 29F040A-90 (FLASH) ;/BIOS on these chip(s) or so?
+ IC901 4pin 37, 69 ;\on back side
+ IC902 4pin 37, 69 ;/
+ ICxxx? 28pin "DALLAS, DS1230Y-100, NONVOLATILE SRAM"
+ U28 20pin LVT244A
+ Z1 20pin LVT244A ;\on back side
+ Z2 20pin LVT245A <-- ;/
+ Z3 20pin LVT244A
+ Z4 20pin LVT244A ;\
+ Z5 20pin LVT245A <-- ; on back side
+ Z6 20pin LVT244A ;/
+ Z7 20pin LVT244A
+ Z8 20pin LVT244A
+ Z9 20pin LVT244A
+ X101 4pin RC67.73, JVC 5L (67.7376MHz oscillator for main cpu)
+ X201 4pin JC53.20, JVC 6A (for GPU, PAL)
+ X202 4pin JC53.69, JVC 6A (for GPU, NTSC)
+ X302 3pin 4.000MHz (for sub-cpu)
+
+Sony DTL-H2700 Dev board (ISA bus) (CPU, ANALYZER ...?)
+Another revision of the DTL-H2000/DTL-H2500 boards. Consists of a single ISA
+card stacked together with two huge daughterboards, and probably additionally
+having a small connector daughterboard. Exact chipset is unknown (there might
+be components on both sides of the PCBs, most of them not visible due to the
+PCB stacking, so taking photos/scans of the PCBs would require advanced
+techniques with screwdrivers).
+Currently the only known chip name is an EPROM (MX 27C1000DC-90, with sticker
+"Title=DTL-H2700, Ver=1.00, Date=96.12.4, Sum=046B No."). The ISA card is
+having markings: "SONY HCD MWB-7? MADE IN JAPAN, PA47 1-589-003-01 1642E03A0".
+One uncommon feature is an extra connector for a "trigger switch" (foot pedal),
+which is reportedly used for activating performance analyzer logging.
+
+Sony DTL-H201A / DT-HV - Graphic Artist Board (IBM PC/ATs to NTSC video)
+ X2 xpin TXC-2 OSC 66.000MHz
+ X1 xpin TXC-2AOSC 53.693MHz
+ U16 14pin 74F74 (dual flipflop)
+ U29 14pin 74AS04 (hex inverters)
+ U14 20pin LVT244 (dual 4-bit 3-state noninverting buffer/line driver)
+ U18 20pin LVT244 (dual 4-bit 3-state noninverting buffer/line driver)
+ U15 20pin ACT244 (dual 4-bit 3-state noninverting buffer/line driver)
+ U11 84pin Altera EPM7096LC84-12 (sticker: "artpc13" or "ARTPC13")
+ U13 160pin Sony CXD8514Q ;GPU'a
+ U5 14pin ALS38A ? (quad open-collector NAND gates with buffered output)
+ U27 20pin ALS244AJ ? (dual 4bit tristate noninverting buffer/line driver)
+ Q1 3pin T B596
+ U23 64pin KM4216V256G-60 (DRAM 256Kx16) ;dual-ported VRAM
+ U22 64pin KM4216V256G-60 (DRAM 256Kx16) ;dual-ported VRAM
+ U28 64pin Sony CXD2923AR ;GPU'b
+ S1 16pin 8bit DIP switch (select I/O address A15..A8)
+ S2 8pin 4bit DIP switch (select I/O address A7..A4)
+ U1 20pin SN74ALS688N (8bit inverting identity comparator with enable)
+ U2 20pin SN74ALS688N (8bit inverting identity comparator with enable)
+ U3 20pin ALS245A (8bit tristate noninverting bus transceiver)
+ JP9 12pin Jumper (6x2 pins) (select IRQ15/IRQ11/IRQ10/IRQ9/IRQ5/IRQ3)
+ U26 24pin Sony CXA1145M ? ;RGB?
+ JP10 3pin Jumper ;\
+ JP12 3pin Jumper ; select "S" or "O" (?)
+ JP11 3pin Jumper ;/
+ J3 2pin? Yellow connector (composite video out?)
+ J2? pin? Mini DIN? connector (maybe S-video out?)
+ J1 15pin High Density SubD (maybe video multi out?)
+ CJx 98pin ISA Bus Cart-edge (2x31 basic pins, plus 2x18 extended pins)
+
+DTL-S2020 aka Psy-Q CD Emu
+ Yellow PCB "CD Emulator System, (C) Cirtech & SN Systems Ldt, 1994 v1.2"
+ IC 24pin GAL20V8B
+ IC 68pin Analog Devices ADSP-2101 (16bit DSP Microprocessor)
+ IC 20pin HD74HC244P
+ IC15 20pin HD74HC244P
+ IC14 20pin CD74HCT245E
+ IC7 28pin 27C512-10 (EPROM 64Kx8) (yellow sticker, without text)
+ IC 28pin HY62256ALP-70 (SRAM 32Kx8)
+ IC12 28pin HY62256ALP-70 (SRAM 32Kx8)
+ IC 28pin HY62256ALP-70 (SRAM 32Kx8)
+ IC13 84pin Emulex/QLogic FAS216 (Fast Architecture SCSI Processor)
+ IC5 84pin Emulex/QLogic FAS216 (Fast Architecture SCSI Processor)
+ IC4 24pin GAL20V8B (near IO Addr jumpers)
+ IC 20pin 74LS244B1 (near lower 8bit of ISA databus)
+ IC 20pin SN74LS245N? (near lower 8bit of ISA databus)
+ IC 20pin SN74LS245N (near upper 8bit of ISA databus)
+ DMA 12pin Jumpers (select DMA7/6/5)
+ IRQ 12pin Jumpers (select IRQ15/12/11/10/7/5)
+ IO 16pin Jumpers (select IO Addr 300/308/310/318/380/388/390/398)
+ SCSI 6pin Jumpers (select SCSI ID 4/2/1) (aka 3bit 0..7 ?)
+ PL3 34pin Connector to DTL-H2000 ?
+ PL1 50pin Connector to INTERNAL SCSI hardware ?
+ PL2 50pin? Connector to EXTERNAL SCSI hardware ? (25pin plug/50pin cable?)
+ Jx 98pin ISA Bus Cart-edge (2x31 basic pins, plus 2x18 extended pins)
+Note: There's also a similar ISA cart (DTL-S510B) with less chips and less
+connectors.
+Note: The SN Systems carts seem to have been distributed by Sony (with
+"DTL-Sxxxx" numbers), and also distributed by Psygnosis. The external SCSI
+connectors can be possibly also used with Psy-Q Development Systems for SNES
+and Sega Saturn?
+
+PSY-Q Development System (Psygnosis 1994)
+ 32pin GM76C8128ALLFW85 (SRAM 128Kx8)
+ 44pin ALTERA EPM7032LC44-15T
+ 34pin EMULEX FAS101 (SCSI Interface Processor)
+ 28pin 27C64 (EPROM 8Kx8) (green sticker, without text)
+ 20pin LCX245 (=74245?)
+ 8pin 2112, CPA, H9527 (?)
+ 3pin transistor? voltage regulator?
+ 20pin DIP socket (containing two 10pin resistor networks)
+ 20pin DIP socket (containing two 10pin resistor networks)
+ 2pin CR2032 Battery 3V
+ 68pin Connector to PSX "Parallel I/O" expansion port
+ 25pin Connector to SCSI hardware (to DTL-S510B or DTL-S2020 ISA cart or so?)
+
+Sony DTL-H800 Sound Artist Board (with optical fibre audio out)
+ U15 24pin ?
+ U5 28pin 27C256 (EPROM 32Kx8) (not installed)
+ U7 4pin 67.7376MHz oscillator
+ U8 14pin ?
+ U11 44pin SEC KM416V256B1-8 (DRAM 256Kx16) ;SoundRAM
+ (44pin package with middle 4pin missing, 40pins used)
+ U10 100pin Sony CXD2925Q ;SPU
+ U4 160pin Lattice IspLSI 3256 (sticker: "VER3")
+ U6 128pin Lattice IspLSI xxxx ?
+ U12 48pin ?
+ U13 48pin ?
+ U3 20pin 74ACT244
+ U14 5pin "LM25755, -3.3 P+" ?
+ U2 54pin ?
+ U1 54pin ?
+ U9 ?pin GP1F31T (light transmitting unit for optical fibre cable)
+ ? 124pin PCI bus cart edge connector
+ ? 8pin internal jumper/connector? (7pin installed, 1pin empty)
+Note: There's also a similar board (DTL-H700) for MAC/NuBus instead of PCI bus.
+
+Sony COH-2000 (unknown purpose)
+ U1 14pin SN74ALS388N ?
+ U2 20pin SN74ALS688N (8bit inverting identity comparator with enable)
+ U3 20pin SN74ALS688N (8bit inverting identity comparator with enable)
+ U4 24pin PALxxx ?
+ U5 20pin SN74ALS245AN
+ U6 20pin SN74ALS245AN
+ U7 20pin SN74ALS244N
+ U8 20pin SN74ALS244N
+ U9 20pin SN74ALS245AN
+ U10 20pin SN74ALS245AN
+ U11 20pin SN74ALS244N
+ S2 16pin 8bit DIP switch (ISA 15/14/13/12/11/10/9/8) ;I/O address bit15-8
+ S1 8pin 4bit DIP switch (ISA 7/6/5/4) ;I/O address bit7-4
+ S3 8pin 4bit DIP switch (BISO? 3/2/1/0) ;BISO? or BISD? or 8150?
+ JPxx .... several jumpers (unknown purpose)
+ Jx 98pin ISA Bus Cart-edge (2x31 basic pins, plus 2x18 extended pins)
+ J5 68pin Connector on rear side (unknown purpose)
+Unknown what COH-2000 was used for. One theory was that it's related to
+PSX-based arcade cabinets. The 68pin connector might be also related to the
+68pin PSX "Parallel I/O" expansion port.
+
+Sony DTL-H2010 (Black External CDROM Drive for DTL-H2000, CD-R compatible)
+External front loading CDROM drive with Eject button. Connects to the blue
+40pin connector on DTL-H2000 boards.
+ IC101 100pin SONY CXD2515Q (Signal Processor + Servo Amp) ;\
+ IC102 28pin BA6297AFP ; on mainboard
+ ICxx 20pin SONY CXA1571N (RF Amp) (on tiny daughtboard) ; (HCMK-81X)
+ CN101 21pin connector to DEX2010.SCH board ;
+ CN10x 12pin connector to KSS-240A (laser pickup) ;
+ S101 2pin pos0 switch or so? ;
+ M101 2pin spindle motor ;/
+ U1 20pin 74ALS244BN ;\
+ U2 20pin 74ALS244BN ;
+ U3 20pin 74ALS244BN ; on DEX2010.SCH board
+ J1 2pin connector to EJECT BUTTON ;
+ J2 5pin connector to LOADING MOTOR ;
+ J3 21pin connector to mainboard ;
+ JP1 40pin external connector to DTL-H2000 ;/
+ CN151 5pin connector to DEX2010.SCH board ;\
+ M151 2pin loading motor (eject motor) ; on CDM 14, CMK PSX board
+ S151 2pin OUT SW ;\switches, probably to ;
+ S152 2pin IN SW ;/sense load/eject status ;/
+ CN1 2pin connector to DEX2010.SCH board ;\on DTL-H2010(1) board
+ SW1 2pin eject button ;/
+The required cable consists of a Yamaichi NFS-40a female connector (blue
+connector on DTL-H2000 side), 0.635mm pitch ribbon cable, and 3M Sub-D MDR40
+connector (silver connector on DTL-H2010 side). But caution: the odd/even pins
+on the cable are somewhat swapped, on DTL-H2000 side the wires should be
+ordered 1,2,3,4,..,39,40, but on DTL-H2010 side they should be ordered
+2,1,4,3,..,40,39.
+
+Sony DTL-H2510 (Gray Internal CDROM Drive)
+This is some sort of a mimmicked front loading PC CDROM drive (consisting of a
+tray that contains a normal (top-loading) PSX cdrom drive unit).
+ IC309 80pin Sony CXD2510Q (CDROM Signal Processor)
+ ICxx ?pin Unknown if there are further ICs (eg. CXA1782BR should exist?)
+ CN1 10pin Connector to daughterboard (with drive unit)
+ CN2 4pin Connector to PC power supply (12V/5V and 2xGND)
+ CN3 50pin Connector to DTL-H2500 or so? (need "PCS-E50FC" plug?)
+There is no eject button, unknown if there's some eject motor, or if one does
+need to push/pull drive tray manually.
+
+Sony SCPH-9903 (Gray SCEx-free Playstation)
+A rare SCEx-free Playstation that can boot from CDR's without SCEx strings;
+maybe intended for beta-testers. Marked "Property of Sony Computer
+Entertainment", "U/C".
+
+Hardware Numbers
+----------------
+
+Sony's own hardware (for PSX) (can be also used with PSone)
+ SCPH-1000 PlayStation (1994) (NTSC-J) (with S-Video)
+ SCPH-1001 PlayStation (1995) (NTSC-U/C) (without S-Video)
+ SCPH-1002 PlayStation (199x) (PAL) (without S-Video)
+ SCPH-1010 Digital joypad (with short cable) (1994)
+ SCPH-1020 Memory Card 1Mbits (1994)
+ SCPH-1030 2-button Mouse (with short cable) (1994)
+ SCPH-1040 Serial Link Cable
+ SCPH-1050 RGB Cable (21-pin RGB Connector)
+ SCPH-1060 RFU Cable/Adaptor (antennae connector) (NTSC-JP?) (1995)
+ SCPH-1061 RFU Cable/Adaptor (antennae connector) (NTSC-US?)
+ SCPH-1062 RFU Cable/Adaptor (antennae connector) (PAL)
+ SCPH-1070 Multitap adaptor (four controllers/memory cards on one slot) (1995)
+ SCPH-1080 Digital joypad (with longer cable) (1996)
+ SCPH-1090 2-button Mouse (with longer cable) (1998)
+ SCPH-1100 S Video Cable (1995)
+ SCPH-1110 Analog Joystick (1996)
+ SCPH-1120 RFU Adaptor (antennae connector) (NTSC-JP?) (1996)
+ SCPH-1121 RFU Adaptor (antennae connector) (NTSC-US?)
+ SCPH-1122 RFU Adaptor (antennae connector) (PAL)
+ SCPH-1130 AC Power Cord (1996)
+ SCPH-1140 AV Cable (1997)
+ SCPH-1150 Analog Joypad (with one vibration motor, with red/green led) (1997)
+ SCPH-1160 AV Adaptor (1997)
+ SCPH-1170 Memory Card Triple Pack (three Memory Cards) (1996)
+ SCPH-1180 Analog Joypad (without vibration motors, with red/green led)
+ SCPH-119X Memory Card (X=different colors) (1997)
+ SCPH-1200 Analog Joypad (with two vibration motors) (dualshock) (1997)
+ SCPH-1210 Memory Card Case (1998)
+ SCPH-2000 Keyboard/Mouse adapter (PS/2 to PSX controller port; for Lightspan)
+ SCPH-3000 PlayStation (1995) (NTSC-J) (with the S-video output removed)
+ SCPH-3500 PlayStation Fighting Box (console bundled with 2 controllers)(1996)
+ SCPH-4000 PocketStation (Memory Card with LCD-screen) (1999)
+ SCPH-4010 VPick (guitar-pick controller) (for Quest for Fame, Stolen Song)
+ SCPH-4020 Long Strap for PocketStation (1999)
+ SCPH-4030 Wrist Strap for PocketStation (1999)
+ SCPH-5000 PlayStation (cost reduced) (Japan) (1996) ;\exists in these three
+ SCPH-5001 PlayStation (cost reduced) (North America) ; regions only (not
+ SCPH-5003 PlayStation (Asia) ;/in Europe)
+ SCPH-5500 PlayStation without Cinch sockets (ie. AV Multi Out only) (1996)(J)
+ SCPH-5501 "" North American version of the 5500
+ SCPH-5502 "" European version of the 5500 (shipped with 1 digital joypad)
+ SCPH-5552 Same as SCPH-5502 (but shipped with memcard and 2 digital joypads)
+ SCPH-5903 PlayStation with built-in MPEG Video-CD decoder (Asia-only)
+ SCPH-7000 PlayStation with Dualshock (1997) (Japan)
+ SCPH-7001 PlayStation with Dualshock (199x) (North America)
+ SCPH-7002 PlayStation with Dualshock (199x) (Europe)
+ SCPH-7003 PlayStation with Dualshock (199x) (Asia)
+ SCPH-7000W PlayStation (10 million model, not for sale, blue, region free)
+ SCPH-7500 PlayStation with Dualshock, cost reduced (1999) (Japan)
+ SCPH-7501 PlayStation with Dualshock, cost reduced (199x) (North America)
+ SCPH-7502 PlayStation with Dualshock, cost reduced (199x) (Europe)
+ SCPH-7503 PlayStation with Dualshock, cost reduced (199x) (Asia)
+ SCPH-9000 PlayStation without Parallel I/O port (1999) (Japan)
+ SCPH-9001 PlayStation without Parallel I/O port (199x) (North America)
+ SCPH-9002 PlayStation without Parallel I/O port (199x) (Europe)
+ SCPH-9003 PlayStation without Parallel I/O port (199x) (Asia)
+ SCPH-9903 Rare SCEx-free PSX (Property of Sony Computer Entertainment, U/C)
+ SCPH-1000R PlayStation Classic (2018) (ARM CPU with emulated PSX games)
+ SFX-100 PlayStation Super Disc Prototype (with SNES chipset, no PSX chips)
+
+Sony's own hardware (for PSone)
+ SCPH-100 PSone (miniaturized PlayStation) (2000) (Japan)
+ SCPH-101 PSone (miniaturized PlayStation) (200x) (North America)
+ SCPH-102 PSone (miniaturized PlayStation) (200x) (Europe)
+ SCPH-103 PSone (miniaturized PlayStation) (200x) (Asia)
+ SCPH-102A PSone Europe (UK/AU, with A/V cable) ;\revision of "SCPH-102"
+ SCPH-102B PSone Europe (UK, with RFU adaptor) ; with PM-41(2) board ?
+ SCPH-102C PSone Europe (Continent, with A/V cable) ;/
+ SCPH-110 Dual Analog Pad (for PSone) (Dualshock) (2000)
+ SCPH-111 Multitap for PSone (seems to be quite rare, except in brazil)
+ SCPH-112 AC adapter for PSone (In: 110-220VAC, Out: 7.5VDC, 2.0A, Japan)
+ SCPH-113 AC adapter for PSone (In: 120VAC/60Hz, Out: 7.5VDC, 2.0A, USA)
+ SCPH-114 AC adapter for PSone (In: 220-240VAC, Out: 7.5VDC, 2.0A, Europe)
+ SCPH-115 AC adapter for PSone (In: 220-240VAC, Out: 7.5VDC, 2.0A, UK)
+ SCPH-116 AC adapter for PSone (In: 220-240VAC, Out: 7.5VDC, 2.0A, Australia)
+ SCPH-117 AC adapter for PSone (In: 110VAC, Out: 7.5VDC, 2.0A, Asia?)
+ SCPH-120 AC adapter for PSone with LCD Screen (In: 100VAC, Out: 7.5VDC, 3.0A)
+ SCPH-130 LCD Screen for PSone (to be attached to the console) (2001)
+ SCPH-140 PSone and LCD screen combo (2001)
+ SCPH-152 LCD screen for PSone (PAL SCPH-152C)
+ SCPH-162 PSone and LCD screen (PAL SCPH-162C)
+ SCPH-170 Car Adapter for PSone from car cigarette lighter (2001)
+ SCPH-180 AV Connection Cable for LCD-screen's AV IN
+ SCPH-10180K DoCoMo I-Mode Adaptor Cable (for internet via mobile phones)
+
+Sony's own devkits
+ DTL-H201A Graphic Artist Board (ISA bus) (with NTSC video out)
+ DTL-H240 PS-X RGB Cable
+ DTL-H500C Digital joypad prototype (SNES-style design, with DB9 connector)
+ DTL-H505 PS-X (Code Name) Target Box ? (PSX prototype, SCSI instead CDROM?)
+ DTL-H700 Sound Artist Board (NuBus for Mac)
+ DTL-H800 Sound Artist Board (PCI Bus for IBM) (with optical fibre sound out)
+ DTL-H1000 Debugging Station (CD-R compatible PSX console) (Japan)
+ DTL-H1001 Debugging Station (CD-R compatible PSX console) (North America)
+ DTL-H1002 Debugging Station (CD-R compatible PSX console) (Europe)
+ DTL-H1030 Mouse ?
+ DTL-H1040 Link Cable ?
+ DTL-H1050 RGB Cable ?
+ DTL-H110x Debugging Station revision? (DC-powered)
+ DTL-H120x Debugging Station revision? (AC-powered)
+ DTL-H1500 Stand-Alone Box ? With ethernet, for SGI Workstation ?
+ DTL-H2000 Dev board v1 (PSX on two ISA carts) (old pre-retail)
+ DTL-H2010 Black External CDROM Drive for DTL-H2000 (CD-R compatible)
+ DTL-H2040 Memory Box ?
+ DTL-H2050 Adaptor for Controller port ?
+ DTL-H2060 Serial Link cable
+ DTL-H2070 RGB Cable ?
+ DTL-H2080 Controller Box (joypad/memcard adaptor for DTL-H2000/DTL-xxxx?)
+ DTL-H2500 Dev board (PCI bus)
+ DTL-H2510 Gray Internal CDROM Drive for DTL-H2500/DTL-H2700 (CD-R compatible)
+ DTL-H2700 Dev board (ISA bus) (CPU, ANALYZER ...?)
+ DTL-H3000 Net Yaroze (hobby programmer dev kit) (Japan)
+ DTL-H3001 Net Yaroze (hobby programmer dev kit) (North America)
+ DTL-H3002 Net Yaroze (hobby programmer dev kit) (Europe)
+ DTL-H3020 Access Card (for yaroze)
+ DTL-H3050 Communication Cable (link port to rs232, for yaroze)
+ DTL-D2020 Documentation: BUILD CD (Manual of Programmer's Tool)
+ DTL-D2120 Documentation: (Manual of Programmer's Tool)
+ DTL-D2130 Documentation: PsyQ (Manual of Programmer's Tool)
+ DTL-D2130 Documentation: SdevTC (Manual of Programmer's Tool)
+ DTL-D2140A Documentation: Ver.1.0 (Manual of Programmer's Tool)
+ DTL-D2150A Documentation: Ver.2.0 (Manual of Programmer's Tool)
+
+SN System / Psy-Q devkit add-ons / SCSI cards
+ DTL-S510B Unknown (another CDROM emulator version?)
+ DTL-S2020 CD-ROM EMULATOR for DTL-H2000/DTL-H2500/DTL-H2700
+
+Sony Licensed Hardware (Japan)
+ SLPH-00001 Namco neGcon (white) (NPC-101), Twist controller (SLEH-0003)
+ SLPH-00002 Hori Fighting stick, digital stick with autofire/slowmotion/rumble
+ SLPH-00003 ASCII Fighter stick V, psx-shaped digital stick (SLEH-0002)
+ SLPH-00004 Sunsoft Sunstation pad, digital pad with autofire/slowmotion
+ SLPH-00005 ASCII ASCIIPAD V, digital pad with autofire/slowmotion
+ SLPH-00006 Imagineer Sandapaddo ThunderPad
+ SLPH-00007 SANKYO N.ASUKA aka Nasca Pachinco Handle, bizarre paddle
+ SLPH-00008 Spital SANGYO Programmable joystick
+ SLPH-00009 Hori Fighting commander 2way controller
+ SLPH-00010 Optec Super Pro Commander
+ SLPH-00011 Super Pro Commander Accessory / Extended memo repack memory
+ SLPH-00012 Hori Fighting Commander 10B Pad (gray), digital pad with extras
+ SLPH-00013 Konami Hyper Blaster (green) ;\IRQ10-based Lightgun
+ SLPH-00014 Konami Hyper Blaster (black) ;/(SLEH-0005/SLUH-00017)
+ SLPH-00015 Namco Volume controller, paddle with 2 buttons
+ SLPH-00016 Waka Up Scan Converter "[chiyo] clean! peripheral equipment?"
+ SLPH-00017 Hori Fighting Commander 10B Pad (black), digital pad with extras
+ SLPH-00018 Hori Real Arcade Stick, digital stick, small L1/L2 (HPS-10)
+ SLPH-00019 Konami Hyperstick
+ SLPH-00020 Imagineer Thunder Pad Transparent
+ SLPH-00021 Imagineer Imagegun
+ SLPH-00022 Optec AI Commander Pro, digital pad with extras / lcd display
+ SLPH-00023 Namco Joystick (SLEH-00004)
+ SLPH-00024 Optec Cockpit Wheel, analog joystick/analog pedals or so
+ SLPH-00025 Optec AI Commander Accessory (extended memo repack ZERO2 version)
+ SLPH-00026 Hori Command Stick PS (SLPH-00026 aka HPS11)
+ SLPH-00027 ASCII Grip, single-handed digital pad (SLEH-00008)
+ SLPH-00028 Hori Grip (gray) (see also: SLPH-00040, and 00086..00088)
+ SLPH-00029 Hori Horipad (clear), digital pad
+ SLPH-00030 Hori Horipad (black), digital pad
+ SLPH-00031 Hori Horipad (gray), digital pad
+ SLPH-00032 Hori Horipad (white), digital pad
+ SLPH-00033 Hori Horipad (blue), digital pad
+ SLPH-00034 Namco G-CON 45, Cinch-based Lightgun (SLEH-0007/SLUH-00035)
+ SLPH-00035 ASCII Fighter stick V Jr. (SLEH-00009)
+ SLPH-00036 Optec Wireless Dual Shot, digital pad with turbo button
+ SLPH-00037 ?
+ SLPH-00038 ASCII Pad V Jr., digital pad without any extras
+ SLPH-00039 ASCII Pad V2 (gray), digital pad with turbo switches (SLEH-00010)
+ SLPH-00040 Hori Grip (black)
+ SLPH-00041 ASCII Grip V
+ SLPH-00042 ASCII Grip V plus (Derby Stallion'99 supplement set), single-hand
+ SLPH-00043 ASCII Pad V2 (clear pink)
+ SLPH-00044 ASCII Pad V2 (clear white)
+ SLPH-00045 ASCII Pad V2 (clear blue)
+ SLPH-00046 ASCII Pad V2 (clear green)
+ SLPH-00047 ASCII Pad V2 (clear black)
+ SLPH-00048 ASCII Pad V2 (clear red/lead?)
+ SLPH-00049 ASCII Pad V2 (clear yellow)
+ SLPH-00050 ASCII Pad V2 (clear orange)
+ SLPH-00051 Taito Streetcar GO! Controller 2 steering "wheel?" tie toe strange
+ SLPH-00052 Koei Video Capture, Ergosoft EGWord, and Lexmark Printer bundle
+ SLPH-00053 Koei Word Processor Ergosoft September EGWORD Ver.2.00
+ SLPH-00054 Hori Zerotech Steering Controller (black)
+ SLPH-00055 Hori Grip (clear blue)
+ SLPH-00056 Hori Grip (clear pink)
+ SLPH-00057 Hori Grip (clear yellow)
+ SLPH-00058 ASCII Pad V2 (gold)
+ SLPH-00059 ASCII Pad V2 (silver)
+ SLPH-00060 ASCII Biohazard, digital pad with re-arranged buttons (SLEH-0011)
+ SLPH-00061 ASCII Pad V2 (pearl white)
+ SLPH-00062 ASCII Pad V2 (pearl blue)
+ SLPH-00063 ASCII Pad V2 (pearl pink)
+ SLPH-00064 ASCII Pad V2 (pearl green)
+ SLPH-00065 ASCII Pad V Pro, with lcd for button-combinations (ASC-0508GX)
+ SLPH-00066 ASCII Arcade Stick 3 "Ultimate"
+ SLPH-00067 ASCII Pad V2 (purple metallic)
+ SLPH-00068 ASCII Pad V2 (lead metallic)
+ SLPH-00069 Namco neGcon (black) (NPC-104), Twist controller (SLEH-0003)
+ SLPH-00070 Sankyo Pachinko FF Controller (alternate to SLPH-00007)
+ SLPH-00071 Hori Command Stick PS Custom
+ SLPH-00072 ASCII Command Pack (memory card add-on or so)
+ SLPH-00073 Optec Wireless digital set (gray) ;\
+ SLPH-00074 Optec Wireless digital set (black) ; pad with receiver
+ SLPH-00075 Optec Wireless digital set (clear) ;
+ SLPH-00076 Optec Wireless digital set (clear blue) ;
+ SLPH-00077 Optec Wireless digital set (clear black) ;/
+ SLPH-00078 Optec Wireless digital shot (gray) ;\
+ SLPH-00079 Optec Wireless digital shot (black) ; extra pad for
+ SLPH-00080 Optec Wireless digital shot (clear) ; second player
+ SLPH-00081 Optec Wireless digital shot (clear blue) ; (without receiver)
+ SLPH-00082 Optec Wireless digital shot (clear black) ;/
+ SLPH-00083 ASCII Stick Justice controller
+ SLPH-00084 Hori ZeroTech Steering Controller (clear)
+ SLPH-00085 Hori Compact joystick (black)
+ SLPH-00086 Hori Compact joystick (clear)
+ SLPH-00087 Hori Compact joystick (clear blue)
+ SLPH-00088 Hori Multi Analog Pad (clear) or Hori Grip (pink?)
+ SLPH-00089 Hori AV Cable with selector
+ SLPH-00090 Hori Multi Analogue Pad (clear black)
+ SLPH-00091 Hori AV Multi-Out Converter
+ SLPH-00092 ASCII Pad V2 (margin green)
+ SLPH-00093 ASCII Pad V2 (margin blue)
+ SLPH-00094 ASCII Pad V2 (margin pink)
+ SLPH-00095 ASCII Pad V2 (margin orange)
+ SLPH-00096 ASCII Hyper Steering V ("high pass tear ring V controller?")
+ SLPH-00097 Hori S Cable with selector (uh, maybe S-video or so?) (HPS-36)
+ SLPH-00098 NSYSCOM Pachinko slot controller (NSC-1)
+ SLPH-00099 ASCII Pad V2 (rainbow)
+ SLPH-00100 ASCII 'Hanging' Fishing Controller, controller for fishing games
+ SLPH-00101 Optec Cockpit big shock
+ SLPH-00102 ASCII Grip V (set for mars story)
+ SLPH-00103 Hori Pad V2 (clear)
+ SLPH-00104 Hori Pad V2 (clear blue)
+ SLPH-00105 Hori Pad V2 (clear pink)
+ SLPH-00106 Hori Pad V2 (black)
+ SLPH-00107 Hori Compact Joystick (camouflage)
+ SLPH-00108 Hori Rumble Digital Pad (clear blue)
+ SLPH-00109 Hori Monoaural AV Cable
+ SLPH-00110 ASCII Pad V2 (marble)
+ SLPH-00111 ASCII Pad V2 (camouflage)
+ SLPH-00112 ASCII Pad V3
+ SLPH-00113 ASCII Pad V3 with cable reel
+ SLPH-00114 ASCII Pad V3 with V2 (pearl white) bundle
+ SLPH-00115 ASCII Pad V3 with V2 (pearl pink) bundle
+ SLPH-00116 ASCII Pad V3 with V2 (pearl blue) bundle
+ SLPH-00117 ASCII Pad V3 (blue) with V2 (pearl green) bundle
+ SLPH-00118 Hori Pad V3
+ SLPH-00119 Hori Pad V3 (white)
+ SLPH-00120 Hori Analog Rumble Pad (clear pink)
+ SLPH-00121 Hori Analog Rumble Pad (clear)
+ SLPH-00122 Hori Analog Rumble Pad (clear blue)
+ SLPH-00123 Hori Analog Rumble Pad (clear red)
+ SLPH-00124 Hori Analog Rumble Pad (clear black)
+ SLPH-00125 Hori Analog Rumble Pad (clear yellow)
+ SLPH-00126 Namco Jogcon, digital pad, steering dial (SLEH-0020/SLUH-00059)
+ SLPH-00127 ?
+ SLPH-00128 ASCII stick ZERO3
+ SLPH-00129 ASCII Pad V2 (wood grain pitch)
+ SLPH-00130 Hori Real Arcade (camouflage)
+ SLPH-00131 Hori Ehrgeiz Stick
+ SLPH-00132 ASCII Pad V3 (blue)
+ SLPH-00133 ASCII Fighter Stick V Jr. (limited edition)
+ SLPH-00134 ASCII Pad V3 (blue) with cable reel
+ SLPH-00135 ASCII Pad V3 (blue) with V2 (silver)
+ SLPH-00136 ASCII Pad V3 with V2 (purple metallic)
+ SLPH-00137 ASCII Pad V3 with V2 (gold)
+ SLPH-00138 ASCII Pad V3 with "VPRO. aka Ascii Fighter Stick V"
+ SLPH-00139 Hori Analog Rumble Pad (gray)
+ SLPH-00140 Hori Analog Rumble Pad (black)
+ SLPH-00141 Hori Analog Rumble Pad (blue)
+And, maybe unlicensed (they don't have official SLPH numbers, still they are
+listed as official controllers on PSX CDROM back covers):
+ ASC-05158B ASCII Beatmania Junk (similar to SLEH-0021)
+ ASC-0528T Sammy Shakkato Tambourine
+ BANC-0001 Bandai Fishing Controller
+ BANC-0002 Bandai Kids Station
+ RU017 Konami Dance Dance Revolution Controller (Dance Mat)
+ GAE001 G.A.E. Baton stick with 2 buttons (for The Maestromusic)
+And whatever:
+ RU029 Konami Beatmania IIDX
+ RU014 Konami Pop'n Music (buttons A,B,C,D,E,F,G,H,I, and Select/Start)
+ ? Produce! Paca Paca Passion
+ ? Sega/Ascii Minimoni Shakatto Tambourine
+
+Sony Licensed Hardware (Europe)
+ SLEH-00001 Ascii Specialized Pad (similar to SLPH-00005: ASCII ASCIIPAD V)
+ SLEH-00002 Ascii Arcade Stick, psx-shaped digital stick (SLPH-00003)
+ SLEH-00003 Namco Negcon, Twist controller (SLPH-00001)
+ SLEH-00004 Namco Arcade Stick (SLPH-00023)
+ SLEH-00005 Konami Hyper Blaster, IRQ10-based Lightgun (SLPH-00014/SLUH-00017)
+ SLEH-00006 Mad Catz Steering Wheel (SLPH-?)
+ SLEH-00007 Namco G-Con 45, Cinch-based Lightgun (SLPH-00034/SLUH-00035)
+ SLEH-00008 Ascii Grip, single-handed digital pad (SLPH-00027/SLUH-00038)
+ SLEH-00009 Ascii Arcade Stick v2 (SLPH-00035)
+ SLEH-00010 Ascii Enhanced Control Pad (similar as SLEH-00001) (SLPH-00039)
+ SLEH-00011 Resident Evil Pad (aka SLPH-00060 ASCII Biohazard)
+ SLEH-00012 Reality-Quest The Glove (right-handed only) (SLUH-00045/SLPH-?)
+ SLEH-00013 CD Case (small nylon bag for fourteen CDs) (SLPH-?)
+ SLEH-00014 ?
+ SLEH-00015 PlayStation Case (bigger bag for the console) (SLPH-?)
+ SLEH-00016 PlayStation Case + Digital Joypad + Memory Card
+ SLEH-00017 ?
+ SLEH-00018 Ascii Sphere 360 (SLUH-00028/SLPH-?)
+ SLEH-00019 Interact V3 Racing Wheel (SLPH-?)
+ SLEH-00020 Namco JogCon, digital pad, steering dial (SLPH-00126/SLUH-00059)
+ SLEH-00021 Konami Beatmania Controller (SLPH-?)
+ SLEH-00022 ?
+ SLEH-00023 Official Dance Mat (RU017/SLUH-00071) (for PSone and PS2)
+ SLEH-00024 Fanatec Speedster 2 (wheel with pedals) (for PSone and PS2)
+ SLEH-00025 Mad Catz 8MB Memory Card (for PS2)
+ SLEH-00026 Olympus Eye-Trek FMD-20P Game/DVD glasses (for PS2)
+ SLEH-00027 Logitech Cordless Controller... or Eye-Trek FMD-20P, too? (PSx?)
+ SLEH-00028 ?
+ SLEH-00029 Fanatec Speedster 3 (for PS2)
+ SLEH-00030 Logitech Eye Toy (camera?) (for PS2)
+And, maybe unlicensed:
+ Weird Madcatz-device (rumble upgrade/add-on for Mad Catz steering wheel)
+
+Sony Licensed Hardware (USA)
+ SLUH-00001 Specialized Joystick (single-axis, digital?)
+ SLUH-00002 Control Pad (redesigned joypad)
+ SLUH-00003 InterAct Piranha Pad, digital pad, autofire/slowmotion
+ SLUH-00017 Konami Justifier, IRQ10-based Lightgun (Hyperblaster/SLPH-00014)
+ SLUH-00018 Enhanced Pad (joypad with whatever extra functions)
+ SLUH-00022 Analog and Digital Steering Wheel with pedals (for testdrive 4?)
+ SLUH-00026 Optec Mach 1 (gray steering/flight controller with pedals)
+ SLUH-00028 Ascii Sphere 360 (SLEH-00018)
+ SLUH-00029 Namco NPC-102 Joystick (single-axis, digital?)
+ SLUH-00031 Interact Program Pad
+ SLUH-00033 Piranha Pad (redesigned joypad)
+ SLUH-00034 NUBY Manufacturing The Heater, white lightgun (irq10 or cinch?)
+ SLUH-00035 Namco G-CON 45, Cinch-based Lightgun (SLEH-0007/SLPH-00034)
+ SLUH-00037 Arcade Stick (single-axis, digital?)
+ SLUH-00038 ASCII Grip V, single-handed digital pad (SLPH-00027/SLEH-00008)
+ SLUH-00040 System Organizer (huh? looks like... a black storage box?)
+ SLUH-00041 V3 Racing Wheel with pedals
+ SLUH-00043 GunCon (bundled with Time Crisis 1)
+ SLUH-00044 Remote Wizard (looks like wireless joypad or so)
+ SLUH-00045 Reality-Quest The Glove (right-handed only) (SLEH-00012/SLPH-?)
+ SLUH-00046 GunCon (bundled with Point Blank)
+ SLUH-00055 Aftershock Wheel with pedals
+ SLUH-00056 UltraRacer Steering Controller (grip-style)
+ SLUH-00057 EA Sports Game Pad (redesigned joypad)
+ SLUH-00058 something for point blank 2 (?) (maybe a lightgun)
+ SLUH-00059 Namco Jogcon, digital pad, steering dial (SLEH-0020/SLPH-00126)
+ SLUH-00061 MadCatz MC2 Racing Wheel (black/gray)
+ SLUH-00063 Bass Landing Fishing Reel controller
+ SLUH-00066 Sportster racing wheel
+ SLUH-00068 Jungle Book Rhythm N Groove Dance Pack
+ SLUH-00071 Konami Dance Pad (DDR Dance Pad) (RU017)
+ SLUH-00072 GunCon (bundled with Point Blank 3)
+ SLUH-00073 GunCon (bundled with Time Crisis 2 - Project Titan)
+ SLUH-00077 Logitech Cordless Controller, analog pad (ps1/ps2)
+ SLUH-00081 Logitech NetPlay Controller, pad with keyboard (usb/ps2)
+ SLUH-00083 Konami Dance Dance Revolution Controller (for PS1 and PS2)
+ SLUH-00084 NYKO iType2, pad with keyboard (usb/ps2)
+ SLUH-00085 Logitech Cordless Action Controller (for PS2)
+ SLUH-00086 Namco/Taiko Drum Master (Taiko Controller Pack) (for PS2)
+ SLUH-00088 RedOctane In the Groove Dance Pad Controller ?
+ SLUH-00090 Dance Pad (bundled with Pump It Up) (for PS2)
+
+Sony Licensed Hardware (Asia)
+ Unknown (if any)
+
+Newer hardware add-ons?
+ SCEH-0001 SingStar (USB to Microfon) (for PS2)
+
+Note
+Early SLEH/SLUH devices used 4-digit numbers (eg. the "official" name for
+SLEH-00003 is SLEH-0003; unlike as shown in the above list).
+
+Software (CDROM Game Codes)
+ SCES-NNNNN Sony Computer Europe Software
+ SCED-NNNNN Sony Computer Europe Demo
+ SLES-NNNNN Sony Licensed Europe Software
+ SLED-NNNNN Sony Licensed Europe Demo
+ SCPS-NNNNN Sony Computer Japan Software
+ SLPS-NNNNN Sony Licensed Japan Software
+ SLPM-NNNNN Sony Licensed Japan ... maybe promo/demo?
+ SCUS-NNNNN Sony Computer USA Software
+ SLUS-NNNNN Sony Licensed USA Software
+ PAPX-NNNNN Demo ...?
+ PCPX-NNNNN Club ...?
+ LSP-NNNNNN Lightspan series (non-retail educational games)
+Note: Multi-disc games have more than one game code. The game code for Disc 1
+is also printed on the CD cover, and used in memory card filenames. The
+per-disk game codes are printed on the discs, and are used as boot-executable
+name in SYSTEM.CNF file. There is no fixed rule for the multi-disc numbering;
+some games are using increasing numbers of XNNNN or NNNNX (with X increasing
+from 0 upwards), and some are randomly using values like NNNXX and NNNYY for
+different discs.
+
+Pinouts
+-------
+
+External Connectors
+--> Pinouts - Controller Ports and Memory-Card Ports
+--> Pinouts - Audio, Video, Power, Expansion Ports
+--> Pinouts - SIO Pinouts
+
+Internal Pinouts
+--> Pinouts - Chipset Summary
+--> Pinouts - CPU Pinouts
+--> Pinouts - GPU Pinouts (for old 160-pin GPU)
+--> Pinouts - GPU Pinouts (for new 208-pin GPU)
+--> Pinouts - SPU Pinouts
+--> Pinouts - DRV Pinouts
+--> Pinouts - VCD Pinouts
+--> Pinouts - HC05 Pinouts
+--> Pinouts - MEM Pinouts
+--> Pinouts - CLK Pinouts
+--> Pinouts - PWR Pinouts
+--> Pinouts - Component List and Chipset Pin-Outs for Digital Joypad, SCPH-1080
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1150
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1200
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-110
+--> Pinouts - Component List and Chipset Pin-Outs for Dualshock2, SCPH-10010
+--> Pinouts - Component List and Chipset Pin-Outs for Namco Lightgun, NPC-103
+--> Pinouts - Component List and Chipset Pin-Outs for Multitap, SCPH-1070
+--> Pinouts - Memory Cards
+
+Mods/Upgrades
+--> Mods - Nocash PSX-XBOO Upload
+--> Mods - PAL/NTSC Color Mods
+
+Pinouts - Controller Ports and Memory-Card Ports
+------------------------------------------------
+
+Controller Ports and Memory-Card Ports
+ 1 In JOYDAT Data from joypad/card (data in) _______________________
+ 2 Out JOYCMD Data to joypad/card (command out) | | | |
+ 3 - +7.5V +7.5VDC supply (eg. for Rumble) | 9 7 6 | 5 4 3 | 2 1 | CARD
+ 4 - GND Ground |_______|_______|_______|
+ 5 - +3.5V +3.5VDC supply (normal supply) _______________________
+ 6 Out /JOYn Select joypad/card in Slot 1/2 | | | |
+ 7 Out JOYCLK Data Shift Clock | 9 8 7 | 6 5 4 | 3 2 1 | PAD
+ 8 In /IRQ10 IRQ10 (Joy only, not mem card) \______|_______|______/
+ 9 In /ACK IRQ7 Acknowledge (each eight CLKs)
+ Shield Ground (Joypad only, not memory card)
+/JOYn are two separate signals (/JOY1 for left card/pad, /JOY2 for right
+card/pad) (whether it is an card or pad access depends on the first CMD bit).
+All other signals are exactly the same on all four connectors (except that pin8
+and shield are missing on the card slots).
+
+Pin8 (/IRQ10)
+Most or all controllers leave pin8 unused, the pin can be used as lightpen
+input (not sure if the CPU is automatically latching a timer somewhere?), if
+there's no auto-latched timer, then the interrupt would be required to be
+handled as soon as possible; ie. don't disable interrupts, and don't "halt" the
+CPU for longer periods (as far as I understood, the GTE can halt the CPU when
+trying to read results of incomplete operations; to avoid that, one could wait
+by software, eg. inserting NOPs, before reading GTE results...?)
+(Some (or maybe all?) existing psx lightguns are reportedly connected to the
+Video output on the Multiout port for determining the current cathode ray
+position though).
+
+Pinouts - Audio, Video, Power, Expansion Ports
+----------------------------------------------
+
+AV Multi Out (Audio/Video Port)
+ 1 RGB-Video Green
+ 2 RGB-Video Red
+ 3 Supply +5.0V (eg. supply for external RF adaptor)
+ 4 RGB-Video Blue
+ 5 Supply Ground
+ 6 S-Video C (chrominance)
+ 7 Composite Video (yellow cinch)
+ 8 S-Video Y (luminance) ____________________________
+ 9 Audio Left (white cinch) | |
+ 10 Audio Left Ground | 12 11 10 9 8 7 6 5 4 3 2 1 |
+ 11 Audio Right (red cinch) |____________________________|
+ 12 Audio Right Ground
+ Shield Video Ground
+The standard AV-cable connects only to Pins 7,9,10,11,12,Shield (with pin 1 and
+3 and Shield shortcut with each other, used for both audio and video ground).
+The plug on that cable does have additional sparings for pin 1,3,5 (though
+without any metal-contacts installed in there) (pin 3,5 would be used as supply
+for external RF modulators) (no idea what pin 1 could be used for though?).
+RGB displays may (or may not) be able to extract /SYNC from the Composite
+signal, if that doesn't work, note that /SYNC (and separate /VSYNC, /HSYNC
+signals) are found on the GPU pinouts, moreover, the GPU outputs 24bit digital
+RGB.
+Not sure if a VGA monitor can be connected? The SYNC signals are there (see GPU
+pinputs), but the vertical resolution is only 200/240 lines... standard VGA
+displays probably support only 400/480 lines (or higher resolutions for newer
+multisync SVGA displays) (as far as I know, the classic 200 lines VGA mode is
+actually outputting 400 lines, with each line repeated twice).
+
+Parallel Port (PIO) (Expansion Port) (CN103)
+This port exists only on older PSX boards (not on newer PSX boards, and not on
+PSone boards).
+The parallel port is used by Gameshark, Game Enhancer II, and Gold Finger cheat
+devices (not used by the Code Breaker CDROM cheat software).
+ ________
+ | | Console Rear View
+ GND ==| 1 35 |== GND .-------------------------.
+ /RESET =| 2 36 |= DACK5 |1 2 3 ... ... 32 33 34|
+ DREQ5 =| 3 37 |= /IRQ10 |35 36 37 ... ... 66 67 68|
+ /EXP? =| 4 38 |= /WR1? (CPU99) |__.-------------------.__|
+ NC?GND? =| 5 39 |= GND?NC?
+ D0 =| 6 40 |= D1
+ D2 =| 7 41 |= D3
+ D4 =| 8 42 |= D5
+ D6 =| 9 43 |= D7
+ D8 =|10 44 |= D9
+ D10 =|11 45 |= D11
+ D12 =|12 46 |= D13
+ D14 =|13 47 |= D15
+ A0 =|14 48 |= A1
+ A2 =|15 49 |= A3
+ NC?GND? =|16 50 |= GND?NC?
+ +3.5V ==|17 51 |== +3.5V
+ +7.5V ==|18 52 |== +7.5V
+ GND? =|19 53 |= GND?NC?
+ A4 =|20 54 |= A5
+ A6 =|21 55 |= A7
+ A8 =|22 56 |= A9
+ A10 =|23 57 |= A11
+ A12 =|24 58 |= A13
+ A14 =|25 59 |= A15
+ A16 =|26 60 |= A17
+ A18 =|27 61 |= A19
+ A20 =|28 62 |= A21
+ A22 =|29 63 |= A23
+ /RD =|30 64 |= /WR0
+ NC!X? =|31 65 |= X?NC!
+ SYSCK? =|32 66 |= LRCK (44.1kHz)
+ SCLK? =|33 67 |= SDATA?
+ GND ==|34 68 |== GND
+ |________|
+Lots of pins are still unknown?
+ EDIT: see http://cgfm2.emuviews.com/new/psx-pio.png
+ apparently, many of the "unknown" pins are just GROUND, is that possible?
+
+Internal Power Supply (PSX)
+The PSX contains an internal power supply, however, like the PSone, it's only
+having a "Standby" button, which merely disconnects 3.5V and 7.9V from the
+mainboard. The actual power supply remains powered, and wastes energy day and
+night, thanks Sony!
+
+External Power Supply (PSone)
+ Inner +7.5V DC 2.0A (inside diameter 0.8mm)
+ Outer GND (outside diameter 5.0mm)
+
+Pinouts - SIO Pinouts
+---------------------
+
+Serial Port
+That port exists only on original Playstation (not on the PSone). The shape of
+the Serial Port is identical to the 12pin Multiout (audio/video) port, but with
+only 8pins.
+ 1 SIO1 In RXD receive data (from remote TXD)
+ 2 SIO2 - VCC +3.5VDC (supply, eg. for voltage conversion)
+ 3 SIO3 In DSR (from remote CTS) _________________
+ 4 SIO4 Out TXD transmit data (to remote RXD) | |
+ 5 SIO5 In CTS clear to send (from remote RTS) | 8 7 6 5 4 3 2 1 |
+ 6 SIO6 Out DTR (to remote DSR) |_________________|
+ 7 SIO7 - GND Ground (supply, eg. for voltage conversion)
+ 8 SIO8 Out RTS request to send (to remote CTS)
+ Shield GND Ground (to/from remote GND)
+Can be used to communicate with another PSX via simple cable connection. With
+an external RS232 adaptor (for voltage conversion) it could be also used to
+communicate with a PC, a mouse, a modem, etc.
+
+PSone Serial Port
+The PSone doesn't have an external serial connector, however, easy to use
+soldering points for serial port signals are found as cluster of 5 soldering
+points (below CPU pin52), and a single soldering point (below CPU pin100),
+arranged like so (on PM-41 boards) (might be different on PM-41(2) boards):
+ CPU70.RTS
+ CPU71.CTS CPU74.TxD
+ CPU72.DTR CPU75.RxD CPU73.DSR
+The three outputs (RTS,DTR,TXD) are left floating, the RXD input is wired via a
+1K ohm pull-up resistor to 3.5V, the other two inputs (CTS,DSR) are wired via
+1K ohm pull-down resistors to GND.
+If you want to upgrade the PSone, remove that resistors, and then install the
+PSX-style serial circuit (as shown below), or, think of a more simplified
+circuit without (dis-)inverted signals.
+
+PSX Serial Port Connection (PU-23 board) (missing on PM-41 board)
+The PSX serial circuit basically consists of a few transistors, diodes, and
+resistors. The relevant part is that most of the signals are inverted -
+compared with RS232 signals, the CPU uses normal high/low levels (of course
+with 0V and 3.5V levels, not -12V and +12V), and the signals at the serial port
+socket are inverted. Ie. if you want to built a RS232 adaptor, you must either
+externally undo the inversion, or, disconnect the transistors, and wire your
+circuit directly to the CPU signals.
+ SIO8 SIO6 SIO4 SIO1 SIO3 SIO5 SIO2 SIO7---GND
+ | | | | | | |
+ FB112 FB114 FB116 FB115 FBnnn FBnnn o--L102-------3.5V
+ | | | | | |
+ | | o-------|-------|-------|--------diode-------GND
+ | | | o-------|-------|--------diode-------GND
+ | | | | o-------|--------diode-------GND
+ | | | | | o--------diode-------GND
+ | | | | | |
+ | | | o-------|-------|--------[1K]--------3.5V
+ | | | | o-------|--------[1K]--------3.5V
+ [22] [22] [22] [22] | o--------[1K]--------3.5V
+ | | | | | |
+ Q105-----|-------|-------|-------|-------|--------------------GND
+ | Q105-----|-------|-------|-------|--------------------GND
+ | | | | Q106-----|--------------------GND
+ | | | | | Q106------------------GND
+ | | | | | |
+ | | | | o-------|--------[470]-------3.5V
+ | | | | | o--------[470]-------3.5V
+ | | | | | |
+ RTS DTR TxD RxD DSR CTS
+ CPU70 CPU72 CPU74 CPU75 CPU73 CPU71 <-- CPU Pin Numbers
+ out out out in in in
+All six signals are passed through fuses (or loops or so). The three inputs
+have 1K ohm pull-ups, and diodes as protection against negative voltages, two
+of the inputs are inverted via transistors, with 470 ohm pull-ups at the CPU
+side, the other input is passed through 22 ohm to the CPU. The three outputs
+are also passed through 22 ohm, one of them having a diode as negative voltage
+protection, the other two are inverted via transistors (which may also serve as
+negative voltage protection).
+Note that there is no positive voltage protection (ie. +12V inputs would do no
+good, also strong -12V inputs might overheat the diodes/fuses, so if you want
+to use RS232 voltages, better use a circuit for voltage conversion).
+
+Serial RS232 Adaptor
+The PSX serial port uses 0V/3.5V logic, whilst RS232 uses -5V/+5V...-15V/+15V
+logic. An example circuit for converting the logic levels would be:
+ PSX.VCC--+||--PSX.GND PSX.GND----DSUB.5.GND----DSUB.SHIELD DSUB.1,9----NC
+ ______ ______
+ ,-----------||+-|1 16|-------PSX.VCC ,-----------||+-|1 16|-------PSX.VCC
+ | PSX.GND---||+-|2 15|-------PSX.GND | PSX.GND---||+-|2 15|-------PSX.GND
+ '---------------|3 14|----DSUB.3.TXD '---------------|3 14|--- N/A
+ ,---+||--|4 13|----DSUB.2.RXD ,---+||--|4 13|--- N/A
+ '--------|5 12|-------PSX.RXD '--------|5 12|--- N/A
+ PSX.GND--+||--|6 11|-------PSX.TXD PSX.GND--+||--|6 11|--- N/A
+ DSUB.7.RTS----|7 10|--o<|--PSX.RTS DSUB.4.DTR----|7 10|--o<|--PSX.DTR
+ DSUB.8.CTS----|8 9|--|>o--PSX.CTS DSUB.6.DSR----|8 9|--|>o--PSX.DSR
+ |______| |______|
+Parts List: 1 or 2 MAX232 chips (voltage conversion), 0 or 1 7400 (NAND, used
+as inverter), 4 or 8 1uF/16V capacitors, 1x 10uF/16V capacitor, 1x 9pin male
+SubD plug.
+The four inverters are needed only for external adapters (which need to undo
+the transistor inversion on the PSX mainboard) (ie. the inverters are not
+needed when when connecting the circuit directly to the PSX CPU).
+The second MAX232 chip is needed only if DTR/DSR "not ready" conditions are
+required (for an "always ready" condition: DSUB.4.DTR can be wired to -8.5V,
+which is available at Pin6 of the first MAX232 chip, and PSX.DSR can be wired
+to +3.5V).
+With the above DSUB pin numbers, peripherals like mice or modems can be
+connected directly to the circuit. For connection to another computer, use a
+"null modem" cable (with crossed RXD/TXD, RTS/CTS, DTR/DSR wires).
+The circuit works with both VCC=5V (default for MAX232) and with VCC=3.5V
+(resulting in slightly weaker signals, but still strong enough even for serial
+mice; which are mis-using the RS232 signals as power supply).
+
+Pinouts - Chipset Summary
+-------------------------
+
+PSX/PSone Mainboards
+ Board Expl.
+ PU-7 PSX, with AV multiout+cinch+svideo, GPU in two chips (160+64pins)
+ PU-8 PSX, with AV multiout+cinch, four 8bit Main RAM chips
+ EARLY-PU-8: "PU-8 1-658-467-11, N4" --> old chipset, resembles PU-7
+ LATE-PU-8: "PU-8 1-658-467-22, N6" --> new chipset, other as PU-7
+ PU-9 PSX, without SCPH-number (just sticker saying "NOT FOR SALE, SONY)
+ PU-16 PSX, with extra Video CD daughterboard (for SCPH-5903)
+ PU-18 PSX, with AV multiout only, single 32bit Main RAM (instead 4x8bit)
+ PU-20 PSX, unknown if/how it differs from PU-18
+ PU-22 PSX, unknown if/how it differs from PU-18
+ PU-23 PSX, with serial port, but without expansion port
+ PM-41 PSone, older PSone, for GPU/SPU with RAM on-board (see revisions)
+ PM-41(2) PSone, newer PSone, for GPU/SPU with RAM on-chip
+There are at least two revisions of the "PM-41" board:
+ PM-41, 1-679-335-21 PSone with incomplete RGB signals on multiout port
+ PM-41, 1-679-335-51 PSone with complete RGB signals on multiout port
+The "incomplete" board reportedly requires to solder one wire to the multiout
+port to make it fully functional... though no idea which wire... looks like the
++5V supply? Also, the capacitors near multiout are arranged slightly
+differently.
+
+CPU chips
+ IC103 - 208pin - "SONY CXD8530BQ" ;seen on PU-7 board
+ IC103 - 208pin - "SONY CXD8530CQ" ;seen on PU-7 and PU-8 boards
+ IC103 - 208pin - "SONY CXD8606Q" ;seen in PU-18 schematic
+ IC103 - 208pin - "SONY CXD8606AQ" ;seen on PU-xx? board
+ IC103 - 208pin - "SONY CXD8606BQ" ;seen on PM-41, PU-23, PU-20 boards
+ IC103 - 208pin - "SONY CXD8606CQ" ;seen on PM-41 board, too
+These chips contain the MIPS CPU, COP0, and COP2 (aka GTE), MDEC and DMA.
+
+GPU chips - Graphics Processing Unit
+ IC203 - 160pin - "SONY CXD8514Q" ;seen on PU-7 and EARLY-PU-8 boards
+ IC203 - 208pin - "SONY CXD8561Q" ;seen on LATE-PU-8 board
+ IC203 - 208pin - "SONY CXD8561BQ" ;seen on PU-18, PU-20 boards
+ IC203 - 208pin - "SONY CXD8561CQ" ;seen on PM-41 board
+ IC203 - 208pin - "SONY CXD9500Q" ;with on-chip RAM ;for PM-41(2) board
+ IC21 - 208pin - "SONY CXD8538Q" ;seen on GP-11 (namco System 11) boards
+ IC103 - 208pin - "SONY CXD8654Q" ;seen on GP-15 (namco System 12) boards
+
+SPU chips - Sound Processing Unit
+ IC308 - 100pin - "SONY CXD2922Q" (SPU) ;PU-7 and EARLY-PU-8
+ IC308 - 100pin - "SONY CXD2922BQ"(SPU) ;EARLY-PU-8
+ IC308 - 100pin - "SONY CXD2925Q" (SPU) ;LATE-PU-8, PU-18, PU-20
+ IC732 - 208pin - "SONY CXD2938Q" (SPU+CDROM) ;PSone/PM-41 Board
+ IC732 - 176pin - "SONY CXD2941R" (SPU+CDROM+SPU_RAM) ;PSone/PM-41(2) Board
+ IC402 - 24pin - "AKM AK4309VM" (Serial 2x16bit DAC);older boards only
+ IC405 - 8pin - "NJM2100E (TE2)" Audio Amplifier ;PU-8 and PU-22 boards
+ IC405 - 14pin - "NJM2174" Audio Amplifier with Mute ;later boards
+
+IC106 CPU-RAM / Main RAM chips
+ IC106/IC107/IC108/IC109 - NEC 424805AL-A60 (28pin, 512Kx8) (PU-8 board)
+ IC106 - "Samsung K4Q153212M-JC60" (70pin, 512Kx32) (newer boards)
+ IC106 - "Toshiba T7X16 (70pin, 512Kx32) (newer boards, too)
+
+GPU-RAM / Video RAM chips
+ IC201 - 64pin NEC uPD482445LGW-A70-S ;VRAM ;\on PU-7 and EARLY-PU-8 board
+ IC202 - 64pin NEC uPD482445LGW-A70-S ;VRAM ;/split into 2 chips !
+ IC201 - 64pin SEC KM4216Y256G-60 ;VRAM ;\on other PU-7 board
+ IC202 - 64pin SEC KM4216Y256G-60 ;VRAM ;/split into 2 chips !
+ IC201 - 100pin - Samsung KM4132G271BQ-10 (128Kx32x2) ;-on later boards
+ IC201 - 100pin - Samsung K4G163222A-PC70 (256Kx32x2) ;-on PM-41
+Note: The older 64pin VRAM chips are special dual-ported DRAM, the newer 100pin
+VRAM chips are just regular DRAM.
+Note: The PM-41 board uses a 2MB VRAM chip (but allows to access only 1MB)
+Note: The PM-41(2) board has on-chip RAM in the GPU (no external memory chip)
+
+IC310 - SPU-RAM - Sound RAM chips
+ IC310 - 40pin - "TOSHIBA TC51V4260DJ-70" ;seen on PU-8 board
+ IC310 - 40pin - EliteMT M11B416256A-35J (256K x 16bit)
+Note: The PM-41(2) board has on-chip RAM in the SPU (no external memory chip)
+
+BIOS ROM
+ IC102 - 40pin - "SONY ..." ;seen on PU-7 & early-PU-8 board (40pin!)
+ IC102 - 44pin - "SONY M538032E-02" ;seen on PU-16 (video CD, 1Mbyte BIOS)
+ IC102 - 32pin - "SONY M534031C-25" ;seen on later-PU-8 board
+ IC102 - 32pin - "SONY 2030" ;seen on PU-18 board
+ IC102 - 32pin - "SONY M534031E-47" ;seen on PM-41 board and PM-41(2)
+ IC102 - 32pin - "SONY M27V401D-41" ;seen on PM-41 board, too
+
+Oscillators and Clock Multiplier/Divider
+ X101 - 4pin - "67.737" (NTSC, presumably) ;PU-7 .. PU-20
+ X201 - 2pin - "17.734" (PAL) or "14.318" (NTSC) ;PU-22 .. PM-41(2)
+ IC204 - 8pin - "2294A" (PAL) or <unknown?> (NTSC) ;PU-22 .. PM-41(2)
+
+Voltage Converter (for +7.5V to +5.0V conversion)
+ IC601 - 3pin - "78M05" or "78005" ;used in PSone
+
+Pulse-Width-Modulation Power-Control Chip
+ IC606 16pin/10mm "TL594CD" (alternately to IC607) ;seen on PM-41 board
+ IC607 16pin/5mm "T594" (alternately to IC606) ;seen on PM-41 board, too
+The PM-41 board has locations for both IC606 and IC607, some boards have the
+bigger IC606 (10mm) installed, others the smaller IC607 (5mm), both chips have
+exactly the same pinouts, the only difference is the size.
+
+Reset Generator
+ IC002 - 8pin - <not installed> (would be alternately to IC003) ;\on PSone
+ IC003 - 5pin - <usually installed> ;/
+ IC101 - 5pin - M51957B (Reset Generator) (on PSX-power supply boards)
+
+CDROM Chips
+ U42 80pin SUB-CPU (CXP82300) with piggyback EPROM ;DTL-H2000
+ IC304 80pin SUB-CPU (MC68HC05L16) 80pin package ;PU-7 and EARLY-PU-8
+ IC304 52pin SUB-CPU (MC68HC05G6) 52pin package ;LATE-PU-8 and up
+ IC305 - 100pin SONY CXD1199BQ (Decoder/FIFO) ;PU-7
+ IC305 - 100pin SONY CXD1815Q (Decoder/FIFO) ;PU-8, PU-18
+ IC309 - 100pin SONY CXD2516Q (Signal Processor) ;PU-7 (100pin!)
+ IC309 - 80pin SONY CXD2510Q (Signal Processor) ;PU-8 and DTL-H2510
+ IC702 - 48pin SONY CXA1782BR (Servo Amplifier) ;PU-7, PU-8
+ IC101 - 100pin SONY CXD2515Q (=CXD2510Q+CXA1782BR) ;DTL-H2010
+ IC701 - 100pin SONY CXD2545Q (=CXD2510Q+CXA1782BR) ;PU-18
+ IC720 - 144pin SONY CXD1817R (=CXD2545Q+CXD1815Q) ;PU-20
+ IC102 - 28pin - "BA6297AFP" ;seen on DTL-H2010 drives
+ IC704 - 28pin - "BA6398FP" ;seen on PU-7
+ IC722 - 28pin - "BA6397FP" ;seen on late PU-8
+ IC722 - 28pin - "BA5947FP" ;seen on PM-41 and various boards
+ IC722 - 28pin - "Panasonic AN8732SB" ;seen on PM-41 board
+ ICxxx - 20pin SONY CXA1571N (RF Amplifier) (on DTL-H2010 drives)
+ IC703 - 20pin SONY CXA1791N (RF Amplifier) (on PU-18 boards)
+ IC723 - 20pin SONY CXA2575N-T4 (RF Matrix Amplifier) (on PU-22 .. PM-41(2))
+Note: The SUB-CPU contains an on-chip BIOS (which does exist in at least seven
+versions, plus US/JP/PAL-region variants, plus region-free debug variants).
+
+RGB Chips
+ IC207 64pin "SONY CXD2923AR" VRAM Data to Analog RGB ;\oldest
+ IC501 24pin "SONY CXA1645M" Analog RGB to Composite ;/
+ IC202 44pin "Philips TDA8771H" Digital RGB to Analog RGB ;\old boards
+ IC202 44pin "Motorola MC141685FT" Digital RGB to Analog RGB ;/
+ IC? 48pin "H7240AKV" 24bit RGB to Analog+Composite ;-SCPH-7001?
+ IC502 48pin "SONY CXA2106R-T4" 24bit RGB to Analog+Composite ;-newer boards
+
+MISC
+ CDROM Drive: "KSM-440BAM" ;seen used with PM-41 board
+ IC602 5pin "L/\1B" or "<symbol> 3DR"
+
+Controller/Memory Card Chips
+ U? 24pin "9625H, CFS8121" ;SCPH-1080, digital pad (alternate?)
+ U? ?pin "SC438001" ;SCPH-1080, digital pad (alternate?)
+ U? 32pin "(M), SC401800" ;SCPH-1080, digital pad
+ U? 32pin "(M), SC442116" ;SCPH-xxxx, mouse
+ IC? 64pin "SONY CXD103, -166Q" ;SCPH-1070, multitap
+ U1 42pin "SD657, 9702K3006" ;SCPH-1150, analog pad, single motor
+ U1 42pin "SD657, 9726K3002" ;SCPH-1180, analog pad, without motor
+ U1 44pin "SONY CXD8771Q" ;SCPH-1200, analog pad, two motors (PSX)
+ U1 44pin "SD707, 039 107" ;SCPH-110, analog pad, two motors (PSone)
+ U1 44pin "SD787A" ;SCPH-xxx, analog pad, two motors (PS2?)
+ U? 64pin "SONY CXD8732AQ" ;SCPH-1020, memory card, on-chip FLASH
+ U? XXpin other chips ;SCPH-xxxx, memory card, external FLASH
+ U1 44pin "NAMCO103P" ;NPC-103, namco lightgun
+
+Pinouts - CPU Pinouts
+---------------------
+
+CPU Pinouts (IC103)
+ 1-3.5V 27-GND 53-3.5V 79-3.5V 105-3.5V 131-3.5V 157-3.5V 183-3.5V
+ 2-3.5V 28-DQ12 54-3.5V 80-/JOY1 106-3.5V 132-A5 158-3.5V 184-GD19
+ 3-67/NC 29-DQ11 55-A11:A8 81-JOYCLK 107-D0 133-A6 159-HBLANK 185-GD20
+ 4-67MHz 30-DQ10 56-A10:NC 82-/IRQ7 108-D1 134-A7 160-DOTCLK 186-GD21
+ 5-DQ31 31-DQ9 57-A9 83-JOYCMD 109-D2 135-A8 161-GD0 187-GD22
+ 6-DQ30 32-DQ8 58-A8:NC 84-JOYDAT 110-D3 136-A9 162-GD1 188-GD23
+ 7-DQ29 33-DQ7 59-A7 85-DACK5 111-D4 137-A10 163-GD2 189-GD24
+ 8-DQ28 34-DQ6 60-A6 86-DREQ5 112-D5 138-A11 164-GD3 190-GD25
+ 9-DQ27 35-DQ5 61-A5 87-DMA4 113-D6 139-A12 165-GD4 191-GD26
+ 10-DQ26 36-DQ4 62-A4 88-/SPUW 114-D7 140-A13 166-GD5 192-GD27
+ 11-DQ25 37-DQ3 63-A3 89-/IRQ10 115-D8 141-A14 167-GD6 193-GD28
+ 12-DQ24 38-3.5V 64-A2 90-/IRQ9 116-D9 142-A15 168-GD7 194-GD29
+ 13-DQ23 39-GND 65-GND 91-GND 117-GND 143-GND 169-GD8 195-GND
+ 14-3.5V 40-DQ2 66-3.5V 92-3.5V 118-3.5V 144-3.5V 170-GND 196-3.5V
+ 15-GND 41-DQ1 67-A1 93-GND 119-D10 145-A16 171-3.5V 197-GD30
+ 16-DQ22 42-DQ0 68-A0 94-/IRQ2 120-D11 146-A17 172-GD9 198-GD31
+ 17-DQ21 43-/W 69-3.5V 95-/CD 121-D12 147-A18 173-GD10 199-VBLANK
+ 18-DQ20 44-/RAS1 70-RTS 96-/SPU 122-D13 148-A19 174-GD11 200-GPU12
+ 19-DQ19 45-/RAS 71-CTS 97-/BIOS 123-D14 149-A20 175-GD12 201-33MHzG
+ 20-DQ18 46-/CAS3 72-DTR 98-/EXP 124-D15 150-A21 176-GD13 202-GPU5
+ 21-DQ17 47-/CAS2 73-DSR 99- CPU99 125-A0 151-A22 177-GD14 203-/GWR
+ 22-DQ16 48-/CAS1 74-TxD 100-/WR 126-A1 152-A23 178-GD15 204-/GRD
+ 23-DQ15 49-/CAS0 75-RxD 101-/RD 127-A2 153-GPU.A2 179-GD16 205-/GPU
+ 24-DQ14 50-3.5V 76-/RES 102-/IRQ1 128-A3 154-33MHzS 180-GD17 206-67MHzG
+ 25-DQ13 51-GND 77-/JOY2 103-GND 129-A4 155-GND 181-GD18 207-GND
+ 26-3.5V 52-GND 78-GND 104-GND 130-GND 156-GND 182-GND 208-GND
+Pin5-68 = Main RAM bus. Pin 95-152 = System bus. Pin 102,153,159-206 = Video
+bus.
+ 85=DACK5 93=GND=/CSHTST 199=/INT0 44=/RAS1:NC
+ 86=DREQ5 99=/SWR1=NC 200=DREQ2 45=/RAS0
+ 87=DACK4 100=/SWR0 201=SYSCLK0
+ 88=DREQ4 154=SYSCLK1 202=DACK2
+
+CPU Pinout Notes
+Pin 3,4: 67MHz is Pin3/old or Pin4/new (with Pin3=NC/new or Pin4=GND/old)
+Pin 43,45..49,100,101,125(A0!),201,203..206 are connected via 22 ohm.
+Pin 77,80,81,83 are connected via 470 ohm.
+Pin 82,84,89 are connected via 47 ohm.
+Pin 95,96,97 are connected via 100 ohm.
+Pin 44: goes LOW for a short time once every N us (guessed: maybe /REFRESH ?)
+Pin 4: 67MHz (from IC204.pin5)
+Pin 87/88: SPU-DMA related (/SPUW also permanent LOW for Manual SPU-RAM Write)
+Pin 154: 33MHzS (via 22ohm and FB102 to SPU) (and TESTPOINT near MainRAM pin70)
+Pin 160: DOTCLK (via 22ohm), and IC502.Pin41 (without 22ohm)
+Pin 56,58 are maybe additional address lines for the addressable 8MB RAM.
+The System Bus address lines are latched outputs (containing the most recently
+used /BIOS /EXP /SPU /CD address) (not affected by Main RAM and GPU
+addressing).
+
+Pinouts - GPU Pinouts (for old 160-pin GPU)
+-------------------------------------------
+
+Old 160-pin GPU is used on PU-7 boards and EARLY-PU-8 boards.
+
+IC203 - Sony CXD8514Q - Old 160pin GPU for use with Dual-ported VRAM
+Unlike the later 208pin GPU's, the old 160pin GPU has less supply pins, and, it
+doesn't have a 24bit RGB output (nor any other video output at all), instead,
+it's used with a RGB D/A converter that reads the video data directly from the
+Dual-ported VRAM chips (ie. from special RAM chips with two data busses, one
+bus for GPU read/write access, and one for the RGB video output).
+ 1-VCC 21-GND 41-D16 61-D2 81-D12'a 101-GND 121-D7'b 141-GND
+ 2-GND 22-D31 42-D15 62-D1 82-D11'a 102-DT/OE'b 122-D6'b 142-53MHz
+ 3-/GPU 23-D30 43-VCC 63-D0 83-D10'a 103-DT/OE'a 123-D5'b 143-VCC
+ 4-GPU.A2 24-D29 44-GND 64-GND 84-D9'a 104-/RAS 124-D4'b 144-GND
+ 5-/GRD 25-D28 45-D14 65-VCC 85-D8'a 105-/WE'a 125-D3'b 145-FSC
+ 6-/GWR 26-D27 46-D13 66-A8'a 86-VCC 106-/WE'b 126-D2'b 146-VCC
+ 7-DACK2 27-D26 47-D12 67-A7'a 87-GND 107-/SE 127-D1'b 147-GND
+ 8-/RES 28-VCC 48-D11 68-A6'a 88-D7'a 108-SC 128-D0'b 148-DOTCLK
+ 9-VCC 29-GND 49-D10 69-A5'a 89-D6'a 109-VCC 129-VCC 149-VCC
+ 10-GND 30-D25 50-GND 70-GND 90-D5'a 110-GND 130-GND 150-GND
+ 11-33MHzG 31-D24 51-VCC 71-A4'a 91-D4'a 111-D15'b 131-A8'b 151-MEMCK1
+ 12-VCC 32-D23 52-D9 72-A3'a 92-D3'a 112-D14'b 132-A7'b 152-MEMCK2
+ 13-GND 33-D22 53-D8 73-A2'a 93-D2'a 113-D13'b 133-A6'b 153-BLANK
+ 14-DREQ2 34-D21 54-D7 74-A1'a 94-D1'a 114-D12'b 134-A5'b 154-/24BPP
+ 15-/IRQ1 35-D20 55-D6 75-A0'a 95-D0'a 115-D11'b 135-A4'b 155-/SYNC
+ 16-HBLANK 36-VCC 56-D5 76-GND 96-VCC 116-D10'b 136-A3'b 156-/HSYNC
+ 17-VBLANK 37-GND 57-D4 77-VCC 97-DSF 117-D9'b 137-A2'b 157-/VSYNC
+ 18-high? 38-D19 58-D3 78-D15'a 98-/CAS'b 118-D8'b 138-A1'b 158-VCC
+ 19-high? 39-D18 59-GND 79-D14'a 99-/CAS'a 119-VCC 139-A0'b 159-GND
+ 20-VCC 40-D17 60-VCC 80-D13'a 100-VCC 120-GND 140-VCC 160-67MHzG
+Pin 1-63,148,160 = CPU Bus, Pin 66-139 = VRAM Bus (two chips, A and B), Pin
+142-155 = Misc (CXA and RGB chips), Pin 18-19,156-157 = Test points.
+Pin 3,5,6,11,98,99,102,103,108,148,160 via 22 ohm. Pin 104,105,106 via 100 ohm.
+Pin 107 via 220 ohm. Pin 155 via 2200 ohm. Pin 145 via 220+2200 ohm.
+ 151-? --- (mem clock?)
+ 152-? (mem clock?)
+ 153-BLANK (high in HBLANK & VBLANK)
+ 154-/24BPP (high=15bpp, low=24bpp)
+ 156-/HSYNC rate:65us=15KHz, low:3.5us
+ 157-/VSYNC rate:20ms=50Hz, low:130us=TwoLines
+
+IC207 - SONY CXD2923AR - Digital VRAM to Analog RGB Converter (for old GPU)
+This chip is used with the old 160pin GPU and two Dual-ported VRAM chips. The
+2x16bit databus is capable of reading up to 32bits of VRAM data, and the chip
+does then extract the 15bit or 24bit RGB values from that data (depending on
+the GPU's current color depth).
+The RGB outputs (pin 5,7,9) seem to be passed through transistors and
+capacitors... not sure how the capacitors could output constant voltage
+levels... unless the RGB signals are actually some kind of edge-triggering PWM
+pulses rather than real analog levels(?)
+ 1-test? 9-BLUE 17-GND 25-D0'a 33-D8'a 41-D15'a 49-D7'b 57-D13'b
+ 2-test? 10-Vxx 18-MEMCK1 26-D1'a 34-D9'a 42-D0'b 50-D8'b 58-D14'b
+ 3-Vxx 11-test? 19-/24BPP 27-D2'a 35-D10'a 43-D1'b 51-D9'b 59-D15'b
+ 4-Vxx 12-test? 20-MEMCK2 28-D3'a 36-D11'a 44-D2'b 52-D10'b 60-GND
+ 5-RED 13-test? 21-BLANK 29-D4'a 37-D12'a 45-D3'b 53-D11'b 61-GND
+ 6-Vxx 14-aGND? 22-DOTCLK 30-D5'a 38-D13'a 46-D4'b 54-D12'b 62-GND
+ 7-GREEN 15-aGND? 23-GND 31-D6'a 39-D14'a 47-D5'b 55-GND 63-test?
+ 8-GND 16-aGND? 24-Vxx 32-D7'a 40-GND 48-D6'b 56-Vxx 64-GND
+Pin 5,7,9 = RGB outputs (via transistors and capacitors?), Pin 18-22 = GPU, Pin
+25-59 = VRAM (chip A and B), Pin 1-2,11-13,63 = Test points.
+
+IC201 - 64pin NEC uPD482445LGW-A70-S or SEC KM4216Y256G-60 (VRAM 256Kx16)
+IC202 - 64pin NEC uPD482445LGW-A70-S or SEC KM4216Y256G-60 (VRAM 256Kx16)
+These are special Dual-ported VRAM chips (with two data busses), the D0-D15
+pins are wired to the GPU (for read/write access), the Q0-Q15 pins are wired to
+the RGB D/A converter (for sequential video output).
+ 1-VCC 9-Q2 17-D5 25-/UWE 33-GND 41-DSF 49-Q10 57-VCC
+ 2-/DT/OE 10-D2 18-VCC 26-/RAS 34-A3 42-GND 50-D11 58-D14
+ 3-GND 11-Q3 19-Q6 27-A8 35-A2 43-D8 51-Q11 59-Q14
+ 4-Q0 12-D3 20-D6 28-A7 36-A1 44-Q8 52-GND 60-D15
+ 5-D0 13-GND 21-Q7 29-A6 37-A0 45-D9 53-D12 61-Q15
+ 6-Q1 14-Q4 22-D7 30-A5 38-QSF 46-Q9 54-Q12 62-GND
+ 7-D1 15-D4 23-GND 31-A4 39-/CAS 47-VCC 55-D13 63-/SE
+ 8-VCC 16-Q5 24-/LWE 32-VCC 40-NC 48-D10 56-Q13 64-SC
+The 8bit /LWE and /UWE write signals are shortcut with each other and wired to
+the GPU's 16bit /WE write signal.
+
+IC501 24pin "SONY CXA1645M" Analog RGB to Composite (older boards only)
+ 1-GND1 4-BIN 7-NPIN 10-SYNCIN 13-IREF 16-YOUT 19-VCC2 22-GOUT
+ 2-RIN 5-NC 8-BFOUT 11-BC 14-VREF 17-YTRAP 20-CVOUT 23-ROUT
+ 3-GIN 6-SCIN 9-YCLPC 12-VCC1 15-COUT 18-FO 21-BOUT 24-GND2
+Used only on older boards (eg. PU-7, PU-8, PU-16), newer boards generate
+composite signal via 48pin IC502.
+Pin7 (NPIN aka /PAL): NTSC=VCC, PAL=GND. Pin6 (SCIN aka FSC): Sub Carrier aka
+PAL/NTSC color clock, which can be derived from three different sources:
+ GPU pin 145 (old 160-pin GPU)
+ GPU pin 154 (new 208-pin GPU)
+ IC204 (on later boards, eg. PSone)
+for the color clocks from GPU pins, the GPU does try to automatically generate
+PAL or NTSC clock depending on current frame rate, which is resulting in
+"wrong" color clock when chaning between 50Hz/60Hz mode).
+
+Pinouts - GPU Pinouts (for new 208-pin GPU)
+-------------------------------------------
+
+New 206-pin GPU is used LATE-PU-8 boards and up.
+
+GPU Pinouts (IC203)
+ 1-/GPU 27-GD28 53-GD10 79-D29 105-GND 131-CLK 157-/PAL 183-R3
+ 2-GPU.A2 28-GD27 54-GD9 80-3.5V 106-3.5V 132-GND 158-/VSYNC 184-GND
+ 3-/GRD 29-3.5V 55-GD8 81-GND 107-D17 133-3.5V 159-/HSYNC 185-3.5V
+ 4-/GWR 30-GND 56-GD7 82-D28 108-D16 134-CLK 160-B0 186-R4
+ 5-CPU202 31-GD26 57-GD6 83-D27 109-D7 135-GND 161-B1 187-R5
+ 6-/RES 32-GD25 58-GD5 84-D26 110-D6 136-3.5V 162-B2 188-R6
+ 7-3.5V 33-GD24 59-GD4 85-D25 111-D5 137-(A10) 163-B3 189-R7
+ 8-GND 34-GD23 60-GND 86-D24 112-D4 138-A9/AP 164-GND 190-GND
+ 9-33MHzG 35-GD22 61-3.5V 87-3.5V 113-GND 139-A7 165-3.5V 191-3.5V
+ 10-3.5V 36-GD21 62-GD3 88-GND 114-3.5V 140-A6 166-B4 192-53MHzP
+ 11-GND 37-3.5V 63-GD2 89-D15 115-D3 141-3.5V 167-B5 193-3.5V
+ 12-CPU200 38-GND 64-GD1 90-D14 116-D0 142-GND 168-B6 194-GND
+ 13-/IRQ1 39-GD20 65-GD0 91-D13 117-D1 143-A5 169-B7 195-3.5V
+ 14-HBLANK 40-GD19 66-GND 92-D12 118-D2 144-A4 170-G0 196-53MHzN
+ 15-GND 41-GD18 67-3.5V 93-D11 119-GND 145-A3 171-G1 197-3.5V
+ 16-3.5V 42-GD17 68-(high) 94-D10 120-3.5V 146-GND 172-G2 198-GND
+ 17-VBLANK 43-3.5V 69-(high) 95-D9 121-NC 147-3.5V 173-G3 199-DOTCLK
+ 18-(pull) 44-GND 70-(high) 96-GND 122-/CS 148-A2 174-GND 200-GND
+ 19-(low) 45-GD16 71-3.5V 97-3.5V 123-DSF 149-A1 175-3.5V 201-3.5V
+ 20-GND 46-GD15 72-3.5V 98-D8 124-/RAS 150-A0 176-G4 202-BLANK
+ 21-(low) 47-GD14 73-3.5V 99-D18 125-/CAS 151-3.5V 177-G5 203-(low)
+ 22-3.5V 48-GD13 74-3.5V 100-D19 126-/WE 152-GND 178-G6 204-GND
+ 23-3.5V 49-GD12 75-3.5V 101-D20 127-DQM1 153-FSC 179-G7 205-3.5V
+ 24-GD31 50-GD11 76-GND 102-D21 128-DQM0 154-3.5V 180-R0 206-67MHzG
+ 25-GD30 51-3.5V 77-D31 103-D22 129-GND 155-GND 181-R1 207-GND
+ 26-GD29 52-GND 78-D30 104-D23 130-3.5V 156-/SYNC 182-R2 208-3.5V
+Pin 77..150 = Video RAM Bus. Pin 156..189 = Video Out Bus. Other = CPU Bus. Pin
+153: Sub Carrier (NC on newer boards whick pick color clock from IC204).
+
+GPU Pinout Notes
+Pin 1,3,4,9,122..128,199,206 are connected via 22 ohm.
+Pin 18 has a 4K7 ohm pullup to 3.5V
+Pin 77..118 data lines (DQ0..DQ31) are connected via 82 ohm.
+Pin 192/196: via 220 ohm to IC204.pin1 (53MHz)
+At RAM Side: CKE via 4K7 to 3.5V, and, A8 is GROUNDED!
+DQM0 is wired to both DQM0 and DQM2, DQM1 is wired to both DQM1 and DQM3.
+CLK is wired to both GPU pin 131 and 134.
+RGBnn = IC502 pin nn
+/VSYNC, /HSYNC, (and BLANK?) are test points (not connected to any components).
+/SYNC = (/VSYNC AND /HSYNC). BLANK = (VBLANK OR HBLANK).
+
+IC202 44pin "Philips TDA8771H" Digital to Analog RGB (older boards only)
+Region Japan+Europe: TDA8771AN
+Region America+Asia: MC151854FLTEG or so?
+ 1-IREF 6-GNDd1 11-R1 16-G4 21-B7 26-B2 31-CLK 36-OUTB 41-NC
+ 2-GNDa1 7-VDDd1 12-R0 17-G3 22-B6 27-VDDd2 32-VDDa1 37-NC 42-GNDa2
+ 3-R7 8-R4 13-G7 18-G2 23-B5 28-GNDd2 33-VREF 38-NC 43-VDDa4
+ 4-R6 9-R3 14-G6 19-G1 24-B4 29-B1 34-NC 39-VDDa3 44-OUTR
+ 5-R5 10-R2 15-G5 20-G0 25-B3 30-B0 35-VDDa2 40-OUTG
+Used only LATE-PU-8 boards (and PU-16, which does even have two TDA8771AH
+chips: one on the mainboard, and one on the VCD daughterboard).
+Earlier boards are generating analog RGB via 64pin IC207, and later boards RGB
+via 48pin IC502.
+
+IC502 48pin "SONY CXA2106R-T4" - 24bit RGB video D/A converter
+ 1-(cap) 7-Comp. 13-/PAL 19-R4 25-G7 31-G1 37-B3 43-NC
+ 2-GND 8-Chro. 14-/SYNC 20-5.0V 26-G6 32-G0 38-B2 44-(cap)
+ 3-Red 9-5.0V 15-4.4MHz 21-R3 27-G5 33-B7 39-B1 45-GND
+ 4-Green 10-YTRAP 16-R7 22-R2 28-G4 34-B6 40-B0 46-(cap)
+ 5-Blue 11-NC 17-R6 23-R1 29-G3 35-B5 41-DOTCLK 47-5.0V
+ 6-Lum. 12-NC 18-R5 24-R0 30-G2 36-B4 42-GND 48-(cap)
+Pin 3..8 (analogue outputs) are passed via external 75 ohm resistors.
+Pin 6,7 additionally via 220uF. Pin 8 additionally via smaller capacitor.
+Pin 10 (YTRAP) wired via 2K7 to 5.0V.
+Pin 1,44,46,48 (can) connect via capacitors to ground (only installed for 44).
+The 4.4MHz clock is obtained via 2K2 from IC204.Pin6.
+The /PAL pin can be reportedly GROUNDED to force PAL colors in NTSC mode, when
+doing that, you may first want to disconnect the pin from the GPU.
+Note: Rohm BH7240AKV has same pinout (XXX but with pin7/pin8 swapped?)
+
+Beware
+Measuring in the region near GPU Pin10 is the nocash number one source for
+blowing up components on the mainboard. If you want to measure that signals
+while power is on, better measure them at the CPU side.
+
+Pinouts - SPU Pinouts
+---------------------
+
+IC308 - SONY CXD2922Q (SPU) (on PU-7, EARLY-PU-8 boards)
+IC308 - SONY CXD2925Q (SPU) (on LATE-PU-8, PU-16, PU-18, PU-20 boards)
+ 1-D0 14-D11 27-A8 40-GND 53-3.5V 66-A15 79-5V 92-LRIA
+ 2-D1 15-GND 28-3.5V 41-SYSCK 54-GND 67-A14 80-A3 93-DTIA
+ 3-3.5V 16-D12 29-GND 42-GND 55-D7 68-A13 81-A2 94-BCIB
+ 4-GND 17-D13 30-A9 43-TEST 56-D6 69-A12 82-A1 95-LRIB
+ 5-D2 18-D14 31-/SPU 44-TES2 57-D5 70-A11 83-A0 96-DTIB
+ 6-D3 19-D15 32-/RD 45-D15 58-D4 71-A10 84-/WE0 97-BCKO
+ 7-D4 20-A1 33-/WR 46-D14 59-D3 72-A9 85-/OE0 98-LRCO
+ 8-D5 21-A2 34-DACK 47-D13 60-D2 73-A8 86-/WE1 99-DATO
+ 9-D6 22-A3 35-/IRQ 48-D12 61-D1 74-A7 87-/OE1 100-WCKO
+ 10-D7 23-A4 36-DREQ 49-D11 62-D0 75-A6 88-GND
+ 11-D8 24-A5 37-MUTE 50-D10 63-/RAS 76-A5 89-XCK
+ 12-D9 25-A6 38-/RST 51-D9 64-/CAS 77-A4 90-GND
+ 13-D10 26-A7 39-NC 52-D8 65-GND 78-GND 91-BCIA
+Pin 1..36 = MIPS-CPU bus. Pin 45..87 = SPU-RAM bus (A0,A10-A15,/WE1,OE1=NC).
+Pin 91..99 = Digital serial audio in/out (A=CDROM, B=EXP, O=OUT).
+
+IC732 - SONY CXD2941R (SPU+CDROM+SPU_RAM) (on PM-41(2) boards)
+ 1-DA16 23-FILO 45-LOCK 67-FSTO 89-SCSY 111-XCS 133-HD9 155-VSS5
+ 2-DA15 24-FILI 46-SSTP 68-COUT 90-SCLK 112-XRD 134-HD8 156-HA1
+ 3-DA14 25-PCO 47-SFDR 69-XDRST 91-SQSO 113-XWR 135-HD7 157-HA0
+ 4-VDDM0 26-CLTV 48-SRDR 70-DA11 92-SENS 114-HINT 136-HD6 158-VDDM3
+ 5-DA13 27-AVSSO 49-TFDR 71-DA10 93-DATA 115-XIRQ 137-VDD4 159-XCK
+ 6-DA12 28-RFAC 50-TRDR 72-DA09 94-XLAT 116-VDDM2 138-HD5 160-DTIB
+ 7-LRCK 29-BIAS 51-VSSM1 73-DA08 95-CLOK 117-XSCS 139-HD4 161-BCKO
+ 8-WDCK 30-ASYI 52-FFDA 74-AVSMO 96-XINT 118-XHCS 140-HD3 162-LRCO
+ 9-VDD0 31-AVDDO 53-FRDA 75-AVDMO 97-A4 119-XHRD 141-HD2 163-DAVDD0
+ 10-VSS0 32-ASYO 54-MDP 76-DA07 98-A3 120-XHWR 142-VSS4 164-DAREFL
+ 11-PSSL 33-VC 55-MDS 77-DA06 99-A2 121-DACK 143-HD1 165-AOUTL
+ 12-ASYE 34-CE 56-VDD2 78-VDDM1 100-A1 122-DREQ 144-HD0 166-DAVSS0
+ 13-GND 35-CEO 57-VSS2 79-DA05 101-A0 123-XRST 145-VSSM3 167-DAVSS1
+ 14-C4M 36-CEI 58-MIRR 80-DA04 102-D7 124-VDD3 146-HA9 168-AOUTR
+ 15-C16M 37-RFDC 59-DFCT 81-DA03 103-D6 125-SYSCK 147-HA8 169-DAREFR
+ 16-FSOF 38-ADIO 60-AVSM1 82-DA02 104-D5 126-VSS3 148-HA7 170-DAVDD1
+ 17-XTSL 39-AVDD1 61-AVDM1 83-DA01 105-D4 127-HD15 149-HA6 171-MUTO
+ 18-VDD1 40-IGEN 62-FOK 84-WFCK 106-VSSM2 128-HD14 150-HA5 172-DATO
+ 19-GND 41-AVSS1 63-PWMI 85-SCOR 107-D3 129-HD13 151-HA4 173-MTS3
+ 20-VPCO1 42-TE 64-FSW 86-SBSO 108-D2 130-HD12 152-VDD5 174-MTS2
+ 21-VPCO2 43-SE 65-MON 87-EXCK 109-D1 131-HD11 153-HA3 175-MTS1
+ 22-VCTL 44-FE 66-ATSK 88-SQCK 110-D0 132-HD10 154-HA2 176-MTS0
+
+IC732 - SONY CXD2938Q (SPU+CDROM) (on newer boards) (PM-41 boards)
+ 1-SCLK 27-RFAC 53-TrckR 79-/XINT 105-A0 131-3.5V 157-(tst) 183-A8
+ 2-GNDed 28-GNDed 54-TrckF 80-SQCK 106-3.5V 132-D9 158-(tst) 184-A7
+ 3-GNDed 29-CLTV 55-FocuR 81-SQSO 107-A1 133-D8 159-GND 185-A6
+ 4-SBSO 30-PCO 56-3.5V 82-SENSE 108-A2 134-D7 160-D15 186-A5
+ 5-WFCK 31-FILI 57-FocuF 83-GND 109-A3 135-D6 161-D0 187-GND
+ 6-GNDed 32-FILO 58-SledR 84-GND 110-A4 136-D5 162-D14 188-A4
+ 7-C16M 33-VCTL 59-SledF 85-CD.D7 111-A5 137-3.5V 163-D1 189-A3
+ 8-3.5V 34-VPC02 60-NC 86-CD.D6 112-3.5V 138-D4 164-D13 190-A2
+ 9-C4M 35-VPC01 61-GND 87-CD.D5 113-A6 139-D3 165-3.5V 191-A1
+ 10-GNDed 36-VC 62-NC 88-CD.D4 114-A7 140-D2 166-D2 192-A0
+ 11-4.3MHz 37-FE 63-GND 89-CD.D3 115-A8 141-D1 167-D12 193-3.5V
+ 12-12MHz 38-SE 64-(tst) 90-CD.D2 116-A9 142-D0 168-D3 194-NC
+ 13-V16M 39-TE 65-(tst) 91-CD.D1 117-/IRQ2 143-GND 169-D11 195-(tst)
+ 14-DOUT 40-CE 66-note 92-CD.D0 118-/IRQ9 144-33MHzS 170-D10 196-GND
+ 15-LACK 41-CEO 67-note 93-3.5V 119-/RD 145- 171-D4 197-(tst)
+ 16-WDCK 42-CEI 68-(tst) 94-CD/CS 120-/WR 146-3.48V 172-D9 198-NC
+ 17-3.5Ved 43-RFDC 69-3.5V 95-CD/WR 121-DMA4 147-ZZ11 173-GND 199-NC
+ 18-LOCK 44-ADIO 70-(tst) 96-CD/RD 122-GND 148-GND 174-D5 200-NC
+ 19-GND 45-GND 71-(tst) 97-CD.A0 123-GND 149-GND 175-D8 201-3.5V
+ 20-MDS 46-IGEN 72-(tst) 98-CD.A1 124-/SPUW 150-ZZ7 176-D6 202-NC
+ 21-MDP 47-AVD1 73-(tst) 99-CD.A2 125-D15 151-3.48V 177-D7 203-NC
+ 22-3.5Ved 48-GNDed 74-DATA 100-GND 126-D14 152-/RES 178-/CAS 204-NC
+ 23-AVDO 49-GNDed 75-XLAT 101-CDA3 127-D13 153-3.5V 179-/WE 205-GND
+ 24-ASYO 50-GND 76-CLOK 102-CDA4 128-D12 154-ZZ5 180-3.5V 206-(tst)
+ 25-ASYI 51-GNDed 77-SCOR 103-/CD 129-D11 155-(tst) 181-/OE 207-(tst)
+ 26-BIAS 52-GNDed 78-GND 104-/SPU 130-D10 156-(tst) 182-/RAS 208-GND
+Pin 74..102 = SubCPU. Pin 103..144 = MainCPU. Pin 160..192 = Sound RAM Bus.
+Pin 21 and 53..59 = Drive Motor Control (IC722).
+Pin 1..47 are probably mainly CDROM related.
+Pin 39 "TE9" = IC723.Pin16 - CL709, and via 15K to SPU.39
+Pin 66 connects via 4K7 to IC723.Pin19.
+Pin 67 not connected (but there's room for an optional capacitor or resistor)
+The (tst) pins are wired to test points (but not connected to any components)
+
+CXD2938Q SPU Pinout Notes
+Pin 74,75,76,119,120 are connected via 22 ohm.
+Pin 103,104 are connected via 100 ohm.
+ZZnn = IC405 Pin nn (analog audio related, L/R/MUTE).
+Pin 103..142 = System Bus (BIOS,CPU). Pin 160..192 = Sound RAM Bus.
+Pin 178 used for both /CASL and /CASH (which are shortcut with each other).
+Pin 146 and 151 are 3.48V (another supply, not 3.5V).
+Pin 147 and 150 are connected via capacitors.
+Pin 195 and 197 testpoints are found below of the pin 206/207 testpoints.
+ SPU155 (tst) always low ;=maybe external audio (serial) this?
+ SPU156 (tst) 45kHz (22us) ;=probably 44.1kHz (ext audio sample-rate)
+ SPU157 (tst) 2777kHz (0.36us) ;=probably 64*44.1kHz (ext audio bit-rate)
+ SPU158 (tst) always high ;=maybe external audio (serial) or this?
+SPU.Pin5 connects to MANY modchips
+SPU.Pin42 connects to ALL modchips
+SPU.Pin42 via capacitor to SPU.Pin41, and via resistor?/diode? to IC723.10
+
+CXD2938Q CDROM clocks
+ SPU197 (*) 7.35kHz (44.1kHz/6) (stable clock, maybe DESIRED drive speed)
+ SPU5 (*) 7.35kHz (44.1kHz/6) (unstable clock, maybe ACTUAL drive speed)
+ SPU15 (*) 44.1kHz (44.1kHz*1)
+ SPU16 (*) 88.2kHz (44.1kHz*2)
+ SPU206 (*) circa 2.27MHz
+ SPU70 (*) whatever clock (with SHORT low pulses)
+(*) these frequencies are twice as fast in double speed mode.
+
+CXD2938Q CDROM signals
+ SPU207 fastsignal?
+ SPU195 slowsignal?
+ SPU18 usually high, low during seek or spinup or so
+ SPU44 superslow hi/lo with superfast noise on it
+ SPU73 mainly LOW with occasional HIGH levels...
+ SPU71 LOW=SPIN_OK, PULSE=SPIN_UP/DOWN_OR_STOPPED
+ SPU72 similar as SPU71
+ SPU64 LOW=STOP, HI=SPIN
+ SPU68 always low...?
+ SPU65 whatever?
+ SPU75 mainly HIGH, short LOW pulses when changing speed up/down/break
+
+CXD2938Q CDROM/SPU Testpoints (on PM-41 board)
+ | | SPU73
+ | CXD2938Q (SPU) | SPU72
+ | (on PM-41 board) | SPU70 SPU71
+ | | SPU64 SPU65 SPU68
+ SPU206 SPU207 |_______________________________________|
+ SPU197
+ SPU195 SPU16 SPU44
+ SPU18 SPU5 SPU15
+ SPU12
+
+IC402 - 24pin AKM AK4309VM (or AK4309AVM/AK4310VM) - Serial 2x16bit DAC
+ 1-TST? 4-/PD 7-CKS 10-LRCK 13-NC? 16-AOUTL 19-GNDa 22-VREFH
+ 2-VCCd 5-/RST 8-BICK 11-NC? 14-NC? 17-VCOM 20-NC? 23-VREFL
+ 3-GNDd 6-MCLK 9-SDATA 12-NC? 15-AOUTR 18-VCCa 21-NC? 24-DZF?
+Used only on older boards (eg. PU-8), newer boards seem to have the DAC in the
+208pin SPU.
+No 24pin AK4309VM datasheet exists (however it seems to be same as 20pin
+AK4309B's, with four extra NC pins at pin10-14).
+
+IC405 - "2174, 1047C, JRC" or "3527, 0A68" (on newer boards)
+Called "NJM2174" in service manual. Audio Amplifier with Mute.
+ 1 GND
+ 2 NC ? via 100ohm to multiout pin 9 ;Audio Left (white cinch)
+ 3 OUT-R ?
+ 4 MUTE1 ;specified as LOW = Mute
+ 5 MUTE2 ;specified as HIGH = Mute
+ 6 MUTEC ;unspecified, maybe capacitor, or output based on MUTE1+MUTE2?
+ 7 IN-R via capacitor to SPU.150
+ 8 BIAS
+ 9 NC
+ 10 NC
+ 11 IN-L via capacitor to SPU.147
+ 12 OUT-L ?
+ 13 NC ? via 100ohm to multiout pin 11 ;Audio Right (red cinch)
+ 14 VCC +5.0V (via L401)
+Audio amplifier, for raising the signals to 5V levels.
+
+IC405 - "NJM2100E (TE2)" Audio Amplifier (on older PU-8 and PU-22 boards)
+ 1-ROUT
+ 2-RIN- IC732.SPU.150
+ 3-RIN+
+ 4-GND
+ 5-LIN+
+ 6-LIN- IC732.SPU.147
+ 7-LOUT
+ 8-VCC 4.9V (+5.0V via L401)
+
+Pinouts - DRV Pinouts
+---------------------
+
+IC304 - 52pin/80pin - Motorola HC05 8bit CPU
+--> Pinouts - HC05 Pinouts
+
+IC305 - SONY CXD1815Q - CDROM Decoder/FIFO (used on PU-8, PU-16, PU-18)
+ 1-D0 14-/XINT 27-/HRD 40-GND 53-VDD 66-/MWR 79-GND 92-LRCO
+ 2-D1 15-GND 28-VDD 41-HDRQ 54-GND 67-MDB0 80-CLK 93-WCKO
+ 3-VDD 16-A0 29-GND 42-/HAC 55-MA8 68-MDB1 81-HCLK 94-BCKO
+ 4-GND 17-A1 30-/HWR 43-MA0 56-MA9 69-MDB2 82-CKSL 95-MUTE
+ 5-D2 18-A2 31-HD0 44-MA1 57-MA10 70-MDB3 83-RMCK 96-TD7
+ 6-D3 19-A3 32-HD1 45-MA2 58-MA11 71-MDB4 84-LRCK 97-TD6
+ 7-D4 20-A4 33-HD2 46-T01 59-MA12 72-MDB5 85-DATA 98-TD5
+ 8-D5 21-TD0 34-HD3 47-T02 60-MA13 73-MDB6 86-BCLK 99-TD4
+ 9-D6 22-/HRS 35-HD4 48-MA3 61-MA14 74-MDB7 87-C2PO 100-TD3
+ 10-D7 23-/HCS 36-HD5 49-MA4 62-MA15 75-MDBP 88-EMP
+ 11-/CS 24-HA0 37-HD6 50-MA5 63-MA16 76-XTL2 89-/RST
+ 12-/RD 25-HA1 38-HD7 51-MA6 64-/MOE 77-XTL1 90-GND
+ 13-/WR 26-HINT 39-HDP 52-MA7 65-GND 78-VDD 91-DATO
+Pin 1..20 to HC05 CPU, pin 22..42 to MIPS cpu, pin 43..75 to SRAM cd-buffer.
+The pinouts/registers in CXD1199AQ datasheet are about 99% same as CXD1815Q.
+Note: Parity on the 8bit data busses is NC. SRAM is 32Kx8 (A15+A16 are NC).
+Later boards have this integrated in the SPU.
+
+ICsss - SONY CXA1782BR - CDROM Servo Amplifier (used on PU-8 boards)
+ 1-FEO 7-FE_M 13-RA_O 19-CLK 25-FOK 31-RF_O 37-FE_BIAS 43-LPFI
+ 2-FEI 8-SRCH 14-SL_P 20-XLT 26-CC2 32-RF_M 38-F 44-TEI
+ 3-FDFCT 9-TGU 15-SL_M 21-DATA 27-CC1 33-LD 39-E 45-ATSC
+ 4-FGD 10-TG2 16-SL_O 22-XRST 28-CB 34-PD 40-EI 46-TZC
+ 5-FLB 11-FSET 17-ISET 23-C.OUT 29-CP 35-PD1 41-GND 47-TDFCT
+ 6-FE_O 12-TA_M 18-VCC 24-SENS 30-RF_I 36-PD2 42-TEO 48-VC
+Datasheet exists. Later boards have CXA1782BR+CXD2510Q integrated in CXD2545Q,
+and even later boards have it integrated in the SPU.
+
+IC309 - SONY CXD2510Q - CDROM Signal Processor (used on PU-8, PU-16 boards)
+ 1-FOK 11-PDO 21-GNDa 31-WDCK 41-DA09-XPLCK 51-APTL 61-EMPH 71-DATA
+ 2-FSW 12-GND 22-VLTV 32-LRCK 42-DA08-GFS 52-GND 62-WFCK 72-XLAT
+ 3-MON 13-TEST0 23-VDDa 33-VDD 5V 43-DA07-RFCK 53-XTAI 63-SCOR 73-VDD
+ 4-MDP 14-NC 24-RF 34-DA16-SDTA48 44-DA06-C2PO 54-XTAO 64-SBSO 74-CLOK
+ 5-MDS 15-NC 25-BIAS 35-DA15-SCLK48 45-DA05-XRAOF 55-XTSL 65-EXCK 75-SEIN
+ 6-LOCK 16-VPCO 26-ASYI 36-DA14-SDTA64 46-DA04-MNT3 56-FSTT 66-SQSO 76-CNIN
+ 7-NC 17-VCKI 27-ASYO 37-DA13-SCLK64 47-DA03-MNT2 57-FSOF 67-SQCK 77-DATO
+ 8-VCOO 18-FILO 28-ASYE 38-DA12-LRCK64 48-DA02-MNT1 58-C16M 68-MUTE 78-XLTO
+ 9-VCOI 19-FILI 29-NC 39-DA11-GTOP 49-DA01-MNT0 59-MD2 69-SENS 79-CLKO
+ 10-TEST 20-PCO 30-PSSL 40-DA10-XUGF 50-APTR 60-DOUT 70-XRST 80-MIRR
+Datasheet exists. Later boards have CXA1782BR+CXD2510Q integrated in CXD2545Q,
+and even later boards have it integrated in the SPU.
+
+IC701 - SONY CXD2545Q - Signal Processor + Servo Amp (used on PU-18 boards)
+ 1-SRON 14-TEST 27-TE 40-VDDa 53-DA09-XPLCK 66-FSTI 79-MUTE 92-DFCT
+ 2-SRDR 15-GND 28-SE 41-VDD 54-DA08-GFS 67-FSTO 80-SENS 93-FOK
+ 3-SFON 16-TES2 29-FE 42-ASYE 55-DA07-RFCK 68-FSOF 81-XRST 94-FSW
+ 4-TFDR 17-TES3 30-VC 43-PSSL 56-DA06-C2PO 69-C16M 82-DIRC 95-MON
+ 5-TRON 18-PDO 31-FILO 44-WDCK 57-DA05-XRAOF 70-MD2 83-SCLK 96-MDP
+ 6-TRDR 19-VPCO 32-FILI 45-LRCK 58-DA04-MNT3 71-DOUT 84-DFSW 97-MDS
+ 7-TFON 20-VCKI 33-PCO 46-DA16-SDTA48 59-DA03-MNT2 72-EMPH 85-ATSK 98-LOCK
+ 8-FFDR 21-VDDa 34-CLTV 47-DA15-SCLK48 60-DA02-MNT1 73-WFCK 86-DATA 99-SSTP
+ 9-FRON 22-IGEN 35-GNDa 48-DA14-SDTA64 61-DA01-MNT0 74-SCOR 87-XLAT 100-SFDR
+ 10-FRDR 23-GNDa 36-RFAC 49-DA13-SCLK64 62-XTAI 75-SBSO 88-CLOK
+ 11-FFON 24-ADIO 37-BIAS 50-DA12-LRCK64 63-XTAO 76-EXCK 89-COUT
+ 12-VCOO 25-RFC 38-ASYI 51-DA11-GTOP 64-XTSL/GNDed 77-SQSO 90-VDD
+ 13-VCOI 26-RFDC 39-ASYO 52-DA10-XUGF 65-GND 78-SQCK 91-MIRR
+Datasheet exists. The CXD2545Q combines the functionality of CXA1782BR+CXD2510Q
+from older boards (later boards have it integrated in the SPU). XTAI/XTAO input
+is 16.9344MHz (44.1kHz*180h), with XTSL=GND. Clock outputs are
+FSTO=16.9344MHz/3, FSOF=16.9344MHz/4, C16M=16.9344MHz/1.
+
+IC101 - SONY CXD2515Q - Signal Processor + Servo Amp (used on DTL-H2010)
+Pinouts are same as CXD2545Q, except, three pins are different: Pin24=ADII
+(instead of ADIO), Pin25=ADIO (instead of RFC), Pin68=C4M (instead of FSOF).
+
+IC720 - 144pin SONY CXD1817R (=CXD2545Q+CXD1815Q) ;PU-20
+ 1..48 - unknown
+ 49 - SCOR
+ 50..144 - unknown
+
+IC701 - 8pin chip (on bottom side, but NOT installed) (PU-7 and EARLY-PU-8)
+ 1-8 Unknown (maybe CDROM related, at least it's near other CDROM chips)
+
+IC722 "BA5947FP" or "Panasonic AN8732SB" - IC for Compact Disc Players
+Drive Motor related.
+ 1 to pin24,27
+ 2 SPINDLE - via 15K to SPU21
+ 3 SW (ON/OFF) - IC304.27
+ 4 TRACKING FORWARD
+ 5 TRACKING REVERSE
+ 6 FOCUS FORWARD
+ 7 FOCUS REVERSE
+ 8 GND - CN702 pin 11
+ 9 NC (INTERNAL) - via C731 (10uF) to GND
+ 10 +7.5V (Pow VCC ch1,2)
+ 11 FOCUS COIL (1) - CN702 pin 15
+ 12 FOCUS COIL (2) - CN702 pin 14
+ 13 TRACKING COIL (1) - CN702 pin 16
+ 14 TRACKING COIL (2) - CN702 pin 13
+ 15 SPINDLE MOTOR (1) - CN701 pin 4
+ 16 SPINDLE MOTOR (2) - CN701 pin 3
+ 17 SLED MOTOR (1) - CN701 pin 1
+ 18 SLED MOTOR (2) - CN701 pin 2
+ 19 +7.5V (Pow VCC ch3,4)
+ 20 MUTE - /RES (via 5K6)
+ 21 GND
+ 22 SLED REVERSE
+ 23 SLED FORWARD
+ 24 to pin1
+ 25 via capacitors to pin1
+ 26 BIAS 1.75V
+ 27 to pin1
+ 28 +7.5V (Pre VCC)
+Additionally to the above 28pins, the chip has two large grounded pins (between
+pin 7/8 and 21/22) for shielding or cooling purposes.
+
+IC703 - 20pin - "SONY CXA1791N" (RF Amplifier) (on PU-18 boards)
+ 1 LD O APC amplifier output
+ 2 PD I APC amplifier input
+ 3 PD1 I Input 1 for RF I-V amplifiers
+ 4 PD2 I Input 2 for RF I-V amplifiers
+ 5 GND/VEE - Supply Ground
+ 6 F I Input F for I-V amplifier
+ 7 E I Input E for I-V amplifier
+ 8 VR O DC Voltage Output (VCC+VEE)/2
+ 9 VC I Center Voltage Input
+ 10 NC - NC
+ 11 NC - NC
+ 12 EO O Monitoring Output for I-V amplifier E
+ 13 EI - Gain Adjust for I-V amplifier E
+ 14 TE O Tracking Error Amplifier Output
+ 15 FE_BIAS I BIAS Adjustment for Focus Error
+ 16 FE O Focus Error Amplifier Output
+ 17 RFO O RF Amplifier Output
+ 18 RFI I RF Amplifier Input
+ 19 /LD_ON I APC amplifier ON=GND, OFF=VCC
+ 20 VCC - Supply
+Datasheet for CXA1791N does exist. Later boards have IC703 replaced by IC723.
+Older PU-7/PU-8 boards appear to have used a bunch of smaller components (8pin
+chips and/or transistors) instead of 20pin RF amplifiers.
+
+IC723 - 20pin - "SONY CXA2575N-T4" (RF (Matrix?) Amplifier) (PU-22..PM-41(2))
+ 1-TEIM
+ 2-TEIG
+ 3-VEE GND
+ 4-E via 33K to CN702 pin 4
+ 5-F via 33K to CN702 pin 8
+ 6-PD2 via 36K to CN702 pin 6
+ 7-PD1 via 36K to CN702 pin 7
+ 8-PD to CN702 pin 9
+ 9-LD
+ 10-VC CL710, and CN702.Pin3, and via resistor?/diode? to SPU42
+ 11-LD_ON IC304.Pin49 "LDON" ..... XXX or is that Pin 20 "LD_ON" ?
+ 12-G_CONT ;or AL/TE?
+ 13-RF0 CL704, and...
+ 14-RFM
+ 15-FE CL708, and... (maybe focus error?)
+ 16-TE CL709, and via 15K to SPU.39 (maybe tracking error?)
+ 17-TE0
+ 18-COMP+
+ 19-MIRR via 4K7 to SPU66
+ 20-VCC 3.48V (not 3.5V)
+Used only on PU-22 .. PM-41(2) boards (PU-18 boards used IC703 "CXA1791N", and
+even older boards... maybe had this in CXA1782BR... or maybe had it in a bunch
+of 8pin NJMxxxx chips?).
+There is no CXA2575N datasheet (but maybe some signals do resemble
+CXA2570N/CXA2571N/CXA1791N datasheets).
+
+CN702 CDROM Data Signal socket (PU-23 and PM-41 board)
+ 1-LD to Q701
+ 2-VCC to Q701
+ 3-VC to IC723.Pin10 (and CL710)
+ 4-F- to IC723.Pin4 (via 33K ohm)
+ 5-NC to CL776
+ 6-PD2 to IC723.Pin6 (via 33K ohm)
+ 7-PD1 to IC723.Pin7 (via 33K ohm)
+ 8-E- to IC723.Pin5 (via 33K ohm)
+ 9-M1 to IC723.Pin8
+ 10-VR via 91 ohm to GND
+ 11-GND GND
+ 12-LS /POS0 (switch, GNDed when at head is at inner-most position)
+ 13-FCS+ TRACKING COIL (2) ;\
+ 14-TRK+ FOCUS COIL (2) ; or swapped?
+ 15-TRK FOCUS COIL (1) ;
+ 16-FCS TRACKING COIL (1) ;/
+PU-23 and PM-41 board seem to be using exactly the same Drive, the only
+difference is the length (and folding) of the attached cable.
+
+CN701 CDROM Motor socket (PU-8, PU-18, PU-23, PM-41 boards)
+ 1-SL- SLED MOTOR (1)
+ 2-SL+ SLED MOTOR (2)
+ 3-SP+ SPINDLE MOTOR (2)
+ 4-SP- SPINDLE MOTOR (1)
+
+CLnnn - Calibration Points (PU-23 and PM-41 boards)
+ CL616 +7.5V (PM-41 only, not PM-23) (before power switch)
+ CL617 GND (PM-41 only, not PM-23)
+ CL316 to IC304 pin 21
+ CL704 to IC723.Pin13
+ CL706 GND
+ CL708 to IC723.Pin15
+ CL709 to IC723.Pin16
+ CL710 to IC723.Pin10, and CN702.Pin3
+ CL711 via 1K to IC723.Pin15
+ CL776 to CN702.Pin5
+Probably test points for drive calibration or so.
+
+Pinouts - VCD Pinouts
+---------------------
+
+SCPH-5903 Video CD PlayStation
+
+VCD Mainboard "PU-16, 1-655-191-11" Component List
+The overall design is very close to LATE-PU-8 boards (1-658-467-2x). Changed
+components are IC102/IC304 (different kernel and cdrom firmware),
+C318/C325/C327 (height reduced capacitors for mounting the daughterboard above
+of them). Plus some extra components: Three triple multiplexors (for switching
+between PSX and VCD audio/video), and the daughterboard connector.
+ IC102 44pin SONY, M538032E-02, JAPAN 6465401 (uncommonly big BIOS, 1Mx8)
+ IC304 52pin C 4021 SC430924PB (HC05 sub-cpu, with extra Video CD command 1Fh)
+ C318 2pin S5 ;\tantalum capacitors with lower height (instead
+ C325 2pin CA7 ; of the electrolytic capacitors on PU-8 boards)
+ C327 2pin CA7 ;/
+ ICnnn 16pin 4053C (Triple multiplexor, for Audio LRCK,BCLK,DATA) (PCB top)
+ ICnnn 16pin 4053C (Triple multiplexor, for Video FSC,CSYNC) (PCB bottom)
+ ICnnn 16pin 2283 (Triple multiplexor, for Video R,G,B) (PCB bottom)
+ CNnnn 30pin Connector to daughterboard (PCB top)
+
+VCD Daughterboard "MP-45, 1-665-192-11" Component List
+ IC102 3pin TA78M05F voltage regulator (7.5V to 5V) (Toshiba)
+ IC104 120pin CXD1852AQ Video CD decoder (Sony)
+ IC106 40pin MB814260-70 (256Kx16 DRAM) (Fujitsu) ;see also: IC114
+ IC107 20pin 6230FV 649 115 (OSD, similar to BU6257AFV-E2) (PCB back)
+ IC109 14pin Y2932 (TLC2932 PLL) (TI) (for RGB.DAC.CLK)
+ IC110 44pin TDA8771AH Triple Video DAC for RGB (Philips) (PCB back)
+ IC111 64pin CXP10224-603R 732A02E (MCU) (Sony)
+ IC112 14pin HCT32A (74HCT32 Quad OR gate) (TI) (PCB back) (for RGB.DAC.CLK)
+ IC113 8pin H74 7H (single D-type flip-flop; OSD clock divider) (PCB back)
+ IC114 40pin MB814260-70 (256Kx16 DRAM) (Fujitsu) ;see also: IC106
+ CN101 30pin Male Connector (to female 30pin socket on PU-16 mainboard)
+ X103 2pin 45.00MHz (for VCD decoder chip)
+ X104 4pin 12.000MHz (for MCU chip)
+ X105 2pin 28.636MHz (for VCD decoder chip) (8*3.579545 NTSC clock)
+
+VCD Daughterboard Connector
+ .--.---.
+ GND / 1 2 | GND
+ (CXD1815Q.86) CD.BCLK | 3 4 | CD.LRCK (CXD1815Q.84)
+ (CXD1815Q.87) CD.C2PO | 5 6 | CD.DATA (CXD1815Q.85)
+ GND | 7 8 | CD.SQCK (CXD2510Q.67) CXP.31
+ (TDA.44) VIDEO.OUTR | 9 10 | CD.SQSO (CXD2510Q.66) CXP.29
+ GND | 11 12 | SIO.OUT (HC05.51.PORTF1 to CXP.47)
+ (TDA.40) VIDEO.OUTG | 13 14 | SIO.IN (HC05.50.PORTF0 from CXP.48)
+ GND | 15 16 | SIO.CLK (HC05.52.PORTF2 to CXP.49)
+ (TDA.36) VIDEO.OUTB | 17 18 | VIDEO.FSC (CXD1852AQ.95)
+ GND | 19 20 | VIDEO.CSYNC(CXD1852AQ.96)
+ (PSU.3) 3.5V | 21 22 | 3.5V (PSU.3)
+ (PSU.1) 7.5V | 23 24 | AUDIO.FSXI (CXD1852AQ.103 to VCD)
+ (PSU.7) /RES | 25 26 | AUDIO.DATA (CXD1852AQ.100)
+ (CXD1852AQ.102) AUDIO.BCLK | 27 28 | AUDIO.LRCK (CXD1852AQ.101)
+ GND | 29 30 | GND
+ '--------'
+
+IC104 "Sony CXD1852AQ" (MPEG-1 Decoder for Video CD) (120 pin)
+ 1-GND 16-HD7 31-GND 46-MD4 61-GND 76-G/Y3 91-GND 106-XTL2O
+ 2-XTL0O 17-MA3 32-MA7 47-MD11 62-/VOE 77-G/Y4 92-HSYNC 107-XTL2I
+ 3-XTL0I 18-MA4 33-MA8 48-MD3 63-R/Cr0 78-G/Y5 93-VSYNC 108-VDD
+ 4-VDD 19-MA2 34-/RAS 49-MD12 64-R/Cr1 79-G/Y6 94-FID/FHREF 109-C2PO
+ 5-HA2 20-MA5 35-/MWE 50-MD2 65-R/Cr2 80-G/Y7 95-CBLNK/FSC 110-LRCI
+ 6-HA3 21-MA1 36-/CAS2 51-MD13 66-R/Cr3 81-B/Cb0 96-CSYNC 111-DATI
+ 7-HD0 22-GND 37-/CAS0 52-MD1 67-R/Cr4 82-B/Cb1 97-/SGRST 112-BCKI
+ 8-HD1 23-MA6 38-MD7 53-MD14 68-R/Cr5 83-B/Cb2 98-CLK0O 113-DOIN
+ 9-HD2 24-MA0 39-MD8 54-MD0 69-R/Cr6 84-B/Cb3 99-DOUT 114-/HCS
+ 10-HD3 25-BC 40-MD6 55-MD15 70-R/Cr7 85-B/Cb4 100-DATO 115-/HDT
+ 11-HD4 26-TCKI 41-MD9 56-OSDEN 71-G/Y0 86-B/Cb5 101-LRCO 116-HRW
+ 12-HD5 27-TDI 42-MD5 57-OSDB 72-G/Y1 87-B/Cb6 102-BCKO 117-/HIRQ
+ 13-HD6 28-TENA1 43-MD10 58-OSDG 73-G/Y2 88-B/Cb7 103-FSXI 118-/RST
+ 14-VDD 29-TDO 44-VDD 59-OSDR 74-VDD 89-DCLK 104-VDD 119-HA0
+ 15-GND 30-VST 45-GND 60-VDD 75-GND 90-VDD 105-GND 120-HA1
+The Hxxx pins are for the Host (the 8bit CXP CPU), the Mxxx for the RAM chips,
+the R/G/B pins are 24bit RGB video. Pin36 can be /CAS2 or MA9 (and, the VCD
+daughterboard has alternate solderpads for one large RAM instead of two small
+RAMs).
+
+IC107 "6230FV" (OSD chip, similar to BU6257AFV-E2) (20 pin)
+ 1-SIO.CLK 5-VDD 9-TEST 13-BLK2 17-OSDG
+ 2-SIO./CS 6-/CKOUT 10-GND 14-VC2 18-OSDB
+ 3-SIO.DTA 7-OSCOUT 11-BLK1 15-OSDEN 19-/VSYNC
+ 4-/RESET 8-OSCIN 12-VC1 16-OSDR 20-/HSYNC
+SIO pin1/2/3 are wired to CXP pin38/37/36. OSCIN is the RGB DAC CLK divided by
+two (from H74 chip pin5). OSD/SYNC on pin15-20 connect to the MPEG1 decoder
+chip.
+No datasheet (but pinouts are same/similar as for BU6257AFV, documented in
+several service manuals for tape decks with vcd player: HCD-V5500,
+HCD-V8900/V8900AV, HCD-V909AV).
+
+IC111 "Sony CXP10224-603R" (8bit SPC700 CPU) (64pin LQFP)
+ 1-PB5=TP 17-PD5=/HCS 33-AVREF=VDD 49-PG5/SCK1=HC05.PF2
+ 2-PB4=TP 18-PD4=TP 34-AVDD=VDD 50-PG4=/RST.OUT
+ 3-PB3=HA3 19-PD3=TP 35-PF7/AN7=TP 51-PG3/TO=TP
+ 4-PB2=HA2 20-PD2=TP 36-PF6/AN6=OSD.DTA 52-PA7=TP
+ 5-PB1=HA1 21-PD1=TP 37-PF5/AN5=OSD./CS 53-PA6=TP
+ 6-PB0=HA0 22-PD0=TP 38-PF4/AN4=OSD.CLK 54-PA5=TP
+ 7-PC7=HD7 23-MP/TEST=GND 39-PF3/AN3=GND 55-PA4=TP
+ 8-PC6=HD6 24-XTAL=12MHZ 40-PF2/AN2=GND 56-VPP=VDD
+ 9-PC5=HD5 25-EXTAL=12MHZ 41-PF1/AN1=GND 57-VDD=VDD
+ 10-PC4=HD4 26-VSS=GND 42-PF0/AN0=10KtoGND 58-VSS=GND
+ 11-PC3=HD3 27-/RST=/RES 43-PE3/PWM1=TP 59-PA3=TP
+ 12-PC2=HD2 28-/CS0=VDD 44-PE2/PWM0=TP 60-PA2=TP
+ 13-PC1=HD1 29-SI0=CD.SQSO 45-PE1/INT2/EC=/VSYNC 61-PA1=TP
+ 14-PC0=HD0 30-SO0=TP 46-PE0/INT0=/HIRQ 62-PA0=TP
+ 15-PD7=HRW 31-/SCK0=CD.SQCK 47-PG7/SI1/INT1=HC05.PF1 63-PB7=TP
+ 16-PD6=/HDT 32-AVSS=GND 48-PG6/SO1=HC05.PF0 64-PB6=TP
+Pin 3-15,45,46,50 connect to MPEG1 decoder. Pin 36-38 to OSD. Pin 47-49 to
+HC05.PortF. Pin 27 is /RESET from PSU. Pin 29,31 are SUBQ from CXD2510Q. The
+"TP" pins connect to test points (but seem to be NC otherwise).
+Pinouts are same as in CXP811P24 datasheet (which uses SPC700 instruction set;
+that instruction set is also used by SNES sound CPU).
+
+IC109 "TLC2932" (PLL) (14pin)
+ 1-LOGIC_VDD=5V 5-FIN-B=HSYNC.PLL 9-PFD_INHIBIT=GND 13-BIAS
+ 2-SELECT=5V 6-PFD_OUT 10-VCO_INHIBIT=GND 14-VCO_VDD=5V
+ 3-VCO_OUT=RGB.DAC.CLK.PLL 7-LOGIC_GND=GND 11-VCO_GND=GND
+ 4-FIN-A=FID/FHREF.PLL 8-NC 12-VCO_IN
+Used to generate the CLK for the TDA chip (that is, the dotclk, paused during
+VSYNC, or so?). The same CLK, divided by two, is also used as OSD.OSCIN.
+
+IC112 "74HCT32" (Quad OR gate) (14pin)
+ 1-FID/FHREF.MPEG 4-HSYNC.MPEG 8-(low) 11-RGB.DAC.CLK.TDA 7-GND
+ 2-FID/FHREF.MPEG 5-HSYNC.MPEG 9-GNDed 12-RGB.DAC.CLK.PLL 14-VCC/5V
+ 3-FID/FHREF.PLL 6-HSYNC.PLL 10-GNDed 13-RGB.DAC.CLK.PLL
+Used to sharpen the output from the PLL chip, and to level-shift signals for
+the two PLL inputs from 3.5V to 5V. The input-pairs for the OR gates are
+shortcut with each other, so the chip isn't actually ORing anything.
+
+IC113 "H74 7H" (single D-type flip-flop; OSD clock divider) (8 pin)
+ 1-CLK 2-D 3-/Q 4-GND 5-Q 6-/RES 7-/SET 8-VCC
+Used to divide the RGB DAC CLK by two. CLK comes from TDA.pin31, D and /Q are
+shortcut with each other, /RES and /SET are wired to VDD, and Q goes to
+OSD.OSCIN.
+
+ICnnn "4053C" (Triple multiplexor, for Audio LRCK,BCLK,DATA) (16pin)
+ 1-IN2B=DATA.VCD 5-IN3A=LRCK.SPU 9-SEL3=LRCK.SEL 13-IN1B=BCLK.VCD
+ 2-IN2A=DATA.SPU 6-/OE=GNDed 10-SEL2=DATA.SEL 14-OUT1=BCLK.OUT
+ 3-IN3B=LRCK.VCD 7-VEE=GNDed 11-SEL1=BCLK.SEL 15-OUT2=DATA.OUT
+ 4-OUT3=LRCK.OUT 8-GND=GND 12-IN1A=BCLK.SPU 16-VDD=VDD/3.5V
+The three SEL pins are wired to HC05.PortF3, the three SPU pins are wired via
+10Kohm.
+
+ICnnn "4053C" (Triple multiplexor, for Video FSC,CSYNC) (16pin)
+ 1-IN2B=FSC.VCD 5-IN3A=CSYNC.PSX 9-SEL3=CSYNC.SEL 13-IN1B=GNDed
+ 2-IN2A=FSC.PSX 6-/OE=GNDed 10-SEL2=FSC.SEL 14-OUT1=NCed
+ 3-IN3B=CSYNC.VCD 7-VEE=GNDed 11-SEL1=DUMMY.SEL 15-OUT2=FSC.OUT
+ 4-OUT3=CSYNC.OUT 8-GND=GND 12-IN1A=GNDed 16-VDD=VCC/5V
+The three SEL pins are wired to HC05.PortF3, the two OUTx pins are wired via
+2.2Kohm.
+
+ICnnn "NJM2283" (Triple multiplexor, for Video R,G,B) (16pin)
+ 1-IN1B=R.VCD 5-OUT2=G.OUT 9-IN3B=B.VCD 13-V=VCC/5V
+ 2-SEL1=R.SEL 6-OUT3=B.OUT 10-GND3=81ohm/GND 14-IN2B=G.VCD
+ 3-OUT1=R.OUT 7-SEL3=B.SEL 11-IN2A=G.PSX 15-GND1=GND
+ 4-GND2=GND 8-IN3A=B.PSX 12-SEL2=G.SEL 16-IN1A=R.PSX
+The three SEL pins are wired to HC05.PortF3, the six INxx pins wired through
+resistors and capacitors, the three OUTx pins are wired through capacitors.
+
+Pinouts - HC05 Pinouts
+----------------------
+
+Motorola HC05 chip versions for PSX cdrom control
+ 80pin "4246xx" - MC68HC05L16, on-chip ROM (DTL-H120x & old retail consoles)
+ 80pin "MC68HC705L16CFU" - MC68HC705L16, on-chip ROM (DTL-H100x, and PU-9)
+ 52pin "SC4309xx" - MC68HC05G6, on-chip ROM (newer retail consoles)
+The early DTL-H2000 devboard is also using a 80pin CPU (with piggyback EPROM
+socket), but that CPU is a Sony CXP82300 SPC700 CPU, not a Motorola HC05 CPU.
+
+IC304 - "C 3060, SC430943PB, G63C 185" (PAL/PSone) - CDROM Controller
+Called "MC68HC05G6PB" in service manual (=8bit CPU).
+ 1 NC NC (TEST:DTR/out) (VCD:AVSEL/out) ;-Port F ;PortF.Bit3
+ 2 VDD 3.5V
+ 3 NC NC ;\ ;maybe PortE.Bit7?
+ 4 NC NC ; maybe MSBs of Port E ;maybe PortE.Bit6?
+ 5 NC NC ;/ ;maybe PortE.Bit5?
+ 6 DECA4 SPU102 ;\ ;PortE.Bit4
+ 7 DECA3 SPU101 ; Port E [04h], aka Address/Index ;PortE.Bit3
+ 8 DECA2 SPU99 ; ;PortE.Bit2
+ 9 DECA1 SPU98 ; ;PortE.Bit1
+ 10 DECA0 SPU97 ;/ ;PortE.Bit0
+ 11 VSS GND
+ 12 NDLY GND reserved for factory test, should be wired to VDD, not GND?
+ 13 /RES /RES (via 5K6)
+ 14 OSC1 4.3MHz (SPU11)(used as external clock for some modchips)(low volts)
+ 15 OSC2 NC
+ 16 F-BIAS aka FOK=NC (in SCPH-5500) ;PortB.Bit0
+ 17 CG NC aka CG=CG (in SCPH-5500) ;this IS portb.1! ;PortB.Bit1
+ 18 LMTSW /POS0 (switch, GNDed when head at inner-most position) ;PortB.Bit2
+ 19 DOOR SHELL_OPEN ;PortB.Bit3
+ 20 TEST2 NC ;PortB.Bit4
+ 21 TEST1 to CL316 ;PortB.Bit5
+ 22 COUT NC ;PortB.Bit6
+ 23 SENSE SPU82 ;CXD2510Q.69 ;PortB.Bit7
+ 24 SUBQ SPU81 ;CXD2510Q.66 ;PortC.Bit0
+ 25 NC NC ;NC ;PortC.Bit1
+ 26 SQCK SPU80 ;CXD2510Q.67 ;PortC.Bit2
+ 27 SPEED IC722.Pin3 (SW) ;PortC.Bit3
+ 28 AL/TE ;transistor aka MIRROR=.. (in SCPH-5500) ;ISN'T PortB.Bit1 !
+ 29 ROMSEL ;NC aka ROMSEL=SCLK (in SCPH-5500) ;PortC.Bit5
+ 30 /XINT SPU79 ;CXD1815Q.14 ;PortC.Bit6
+ 31 SCOR SPU77 ;CXD2510Q.63 ;PortC.Bit7
+ 32 VDD 3.5V
+ 33 DECD0 CD.D0 ;\ ;PortA.Bit0
+ 34 DECD1 CD.D1 ; ;PortA.Bit1
+ 35 DECD2 CD.D2 ; ;PortA.Bit2
+ 36 DECD3 CD.D3 ; Port A [00h], aka Data ;PortA.Bit3
+ 37 DECD4 CD.D4 ; ;PortA.Bit4
+ 38 DECD5 CD.D5 ; ;PortA.Bit5
+ 39 VSS GND ;
+ 40 DECD6 CD.D6 ; ;PortA.Bit6
+ 41 DECD7 CD.D7 ;/ ;PortA.Bit7
+ 42 NC NC ;maybe PortD.Bit0?
+ 43 DATA SPU74 (via 22 ohm) ;PortD.Bit1
+ 44 XLAT SPU75 (via 22 ohm) ;PortD.Bit2
+ 45 CLOK SPU76 (via 22 ohm) ;PortD.Bit3
+ 46 DECCS SPU94 ;PortD.Bit4
+ 47 DECWR SPU95 ;PortD.Bit5
+ 48 DECRD SPU96 ;PortD.Bit6
+ 49 LDON IC723.Pin11 ;PortD.Bit7
+ 50 NC NC (TEST:TX/out) (VCD:SIO.IN/in) ;\PortF (used by ;PortF.Bit0
+ 51 NC NC (TEST:RX/in) (VCD:SIO.OUT/out) ; Motorola Testmode;PortF.Bit1
+ 52 NC NC (TEST:RTS/out) (VCD:SIO.CLK/out) ;/and VCD version) ;PortF.Bit2
+This chip isn't connected directly to the CPU, but rather to a Fifo Interface,
+which is then forwarding data to/from the CPU. On older PSX boards, that Fifo
+Interface has been located in a separate chip, on newer PSX boards and PSone
+boards, the Fifo stuff is contained in the SPU chip. The CDROM has a 32K
+buffer, which is also implemeted at the Fifo Interface side.
+OSC input (internally HC05 is running at OSC/2, ie. around 2MHz):
+ PU-8 4.0000MHz from separate 4.000MHz oscillator (X302)
+ PU-16 4.0000MHz from separate 4.000MHz oscillator (X302)
+ DTL-H2000 4.1900MHz from separate 4.1900MHz oscillator (SPC700, not HC05)
+ PU-18 4.2336MHz from CXD2545Q.pin68 (Servo+Signal) (FSOF=16.9344MHz/4)
+ PU-20 4.2xxxMHz from CXD1817R.pin? (Servo+Signal+Decoder)
+ PM-41 4.2xxxMHz from CXD2938Q.pin11 (Servo+Signal+Decoder+SPU)
+
+HC05 - 80pin version (pinout from MC68HC05L16 datasheet)
+ 1 VDD
+ 2 FP28/PE6 ;\
+ 3 FP29/PE5 ;
+ 4 FP30/PE4 ;
+ 5 FP31/PE3 ; Port E LSBs
+ 6 FP32/PE2 ;
+ 7 FP33/PE1 ;
+ 8 FP34/PE0 ;/
+ 9 FP35/PD7 ;\
+ 10 FP36/PD6 ; Port D MSBs
+ 11 FP37/PD5 ;
+ 12 FP38/PD4 ;/
+ 13 VLCD3
+ 14 VLCD2
+ 15 VLCD1
+ 16 VSS
+ 17 NDLY
+ 18 XOSC1
+ 19 XOSC2
+ 20 /RESET
+ ---
+ 21 OSC1
+ 22 OSC2
+ 23 PA0 ;\
+ 24 PA1 ;
+ 25 PA2 ;
+ 26 PA3 ; Port A
+ 27 PA4 ;
+ 28 PA5 ;
+ 29 PA6 ;
+ 30 PA7 ;/
+ 31 PB0/KWI0 ;\
+ 32 PB1/KWI1 ;
+ 33 PB2/KWI2 ;
+ 34 PB3/KWI3 ; Port B
+ 35 PB4/KWI4 ;
+ 36 PB5/KWI5 ;
+ 37 PB6/KWI6 ;
+ 38 PB7/KWI7 ;/
+ 39 PC0/SDI ;\
+ 40 PC1/SDO ;
+ --- ;
+ 41 PC2/SCK ; Port C
+ 42 PC3/TCAP ;
+ 43 PC4/EVI ;
+ 44 PC5/EVO ;
+ 45 PC6/IRQ2 ;
+ 46 PC7/IRQ1 ;/
+ 47 VDD
+ 48 BP3/PD3 ;\
+ 49 BP2/PD2 ; Port D LSBs
+ 50 BP1/PD1 ;
+ 51 BP0 (no "PD0") ;/
+ 52 FP0
+ 53 FP1
+ 54 FP2
+ 55 FP3
+ 56 FP4
+ 57 FP5
+ 58 FP6
+ 59 FP7
+ 60 VSS
+ ---
+ 61 FP8
+ 62 FP9
+ 63 FP10
+ 64 FP11
+ 65 FP12
+ 66 FP13
+ 67 FP14
+ 68 FP15
+ 69 FP16
+ 70 FP17
+ 71 FP18
+ 72 FP19
+ 73 FP20
+ 74 FP21
+ 75 FP22
+ 76 FP23
+ 77 FP24
+ 78 FP25
+ 79 FP26
+ 80 FP27/PE7 ;- Port E MSB
+
+HC05 - 32pin/64pin Versions
+Sony's Digital Joypad and Mouse contain 32pin CPUs, which are probably also
+HC05's:
+--> Pinouts - Component List and Chipset Pin-Outs for Digital Joypad, SCPH-1080
+Moreover, some old memory cards contain a 64pin Motorola SC419510FU (probably
+also a HC05) with separate Atmel AT29LV010A (128Kx8 FLASH).
+
+Pinouts - MEM Pinouts
+---------------------
+
+IC102 - BIOS ROM (32pin, 512Kx8, used on LATE-PU-8 boards, and newer boards)
+ 1-A19 5-A7 9-A3 13-D0 17-D3 21-D7 25-A11 29-A14
+ 2-A16 6-A6 10-A2 14-D1 18-D4 22-/CE 26-A9 30-A17 ;/CE=/BIOS
+ 3-A15 7-A5 11-A1 15-D2 19-D5 23-A10 27-A8 31-A18
+ 4-A12 8-A4 12-A0 16-GND 20-D6 24-/OE 28-A13 32-3.5V ;/OE=/RD
+Uses standard EPROM pinouts, VCC is 3.5V though, when replacing the ROM by an
+EPROM, it may be required to replace the supply by 5V. Note that, on PM-41
+boards at least, Pin 1 is connected to A19 (allowing to install a 1MB BIOS chip
+on that board, however, normally, a 512KB BIOS chip is installed, and, the CPU
+is generating an exception when trying to access more than 512KB, but that 512K
+limit can be disabled via memory control registers).
+Datasheet for (MS-)M534031E does exist.
+
+IC102 - BIOS ROM (40pin, 512Kx8, used on PU-7 boards, and EARLY-PU-8 boards)
+ 1-A18 6-A4 11-GND 16-D9 21-VCC 26-D6 31-GND(/BYTE) 36-A13
+ 2-A8 7-A3 12-/OE 17-D2 22-D4 27-D14 32-A17 37-A12
+ 3-A7 8-A2 13-D0 18-D10 23-D12 28-D7 33-A16 38-A11
+ 4-A6 9-A1 14-D8 19-D3 24-D5 29-A0(D15) 34-A15 39-A10
+ 5-A5 10-/CS 15-D1 20-D11 25-D13 30-GND 35-A14 40-A9
+The chip supports 8bit/16bit mode, on the PSX D0-D14 are actually wired, but
+A0/D15 is wired to A0, and /BYTE is wired to GND, so 16bit mode doesn't work.
+Datasheet for MX23L4100 does exist.
+
+IC102 - BIOS ROM (44pin, 1Mx8, used on P16-boards, ie. VCD console)
+ 1-NC 5-A7 9-A3 13-GND 17-D1 21-D3 25-D12 29-D14 33-/BYT 37-A14 41-A10
+ 2-A19 6-A6 10-A2 14-/OE 18-D9 22-D11 26-D5 30-D7 34-A17 38-A13 42-A9
+ 3-A18 7-A5 11-A1 15-D0 19-D2 23-VCC 27-D13 31-D15/A0 35-A16 39-A12 43-NC
+ 4-A8 8-A4 12-/CE 16-D8 20-D10 24-D4 28-D6 32-GND 36-A15 40-A11 44-NC
+Pinouts are from OKI MSM538032E datasheet.
+
+IC106 - CPU-RAM (single 70pin chip, on newer boards)
+"Samsung K4Q153212M-JC60" (70pin, 512Kx32) (newer boards)
+"Toshiba T7X16" (70pin, 512Kx32) (newer boards, too)
+ 1-VCC 11-N.C 21-DQ15 31-A3 41-N.C 51-DQ17 61-DQ24
+ 2-DQ0 12-VCC 22-N.C 32-A4 42-N.C 52-DQ18 62-DQ25
+ 3-DQ1 13-DQ8 23-N.C! 33-A5 43-/OE 53-DQ19 63-DQ26
+ 4-DQ2 14-DQ9 24-N.C 34-A6 44-/W 54-VSS 64-DQ27
+ 5-DQ3 15-DQ10 25-N.C 35-VCC 45-/CAS3 55-DQ20 65-VSS
+ 6-VCC 16-DQ11 26-N.C 36-VSS 46-/CAS2 56-DQ21 66-DQ28
+ 7-DQ4 17-VCC 27-/RAS 37-A7 47-/CAS1 57-DQ22 67-DQ29
+ 8-DQ5 18-DQ12 28-A0 38-A8 48-/CAS0 58-DQ23 68-DQ30
+ 9-DQ6 19-DQ13 29-A1 39-A9 49-N.C 59-VSS 69-DQ31
+ 10-DQ7 20-DQ14 30-A2 40-N.C 50-DQ16 60-N.C 70-VSS
+Notes: Pin23 must NC or VSS. In the PSone, /OE is wired to GND.
+Datasheet for K4Q153212M-JC60 does exist (the chip supports 27ns Hyper Page
+mode access, which seems to be used for DMA).
+The RAM chip comes up without external /REFRESH signal, but maybe the CPU does
+tweak RAS/CAS to generate refresh (the CPU has some odd delays once and when).
+
+IC106/IC107/IC108/IC109 - CPU-RAM (four 28pin chips, on PU-8, PU-18 boards)
+SEC KM48V514BJ-6 (DRAM 512Kx8) (four pieces = 512Kx32 = 2Mbyte)
+ 1-VCC 5-DQ3 9-A9 13-A3 17-A5 21-NC 25-DQ5
+ 2-DQ0 6-NC 10-A0 14-VCC 18-A6 22-/OE 26-DQ6
+ 3-DQ1 7-/W 11-A1 15-GND 19-A7 23-/CAS 27-DQ7
+ 4-DQ2 8-/RAS 12-A2 16-A4 20-A8 24-DQ4 28-GND
+Datasheet for KM48V514B-6 and BL-6 exist (though none for BJ-6). The chips
+support 25ns Hyper Page mode access.
+
+IC310 - SPU-RAM (512Kbyte)
+EliteMT M11B416256A-35J (256K x 16bit) (40pin SOJ, PM-41 boards)
+Nippon Steel NN514256ALTT-50 (256K x 16bit) (40pin TSOP-II, PU-23 boards)
+Toshiba TC51V4260DJ-70 (40pin, PU-8 board) (PseudoSRAM)
+ 1-5.0V 6-5.0V 11-NC 16-A0 21-VSS 26-A8 31-I/O8 36-I/O12
+ 2-I/O0 7-I/O4 12-NC 17-A1 22-A4 27-/OE 32-I/O9 37-I/O13
+ 3-I/O1 8-I/O5 13-/WE 18-A2 23-A5 28-/CASH 33-I/O10 38-I/O14
+ 4-I/O2 9-I/O6 14-/RAS 19-A3 24-A6 29-/CASL 34-I/O11 39-I/O15
+ 5-I/O3 10-I/O7 15-NC 20-5.0V 25-A7 30-NC 35-VSS 40-VSS
+Note: SPU-RAM supply can be 3.5V (PU-8), or 5.0V (PU-22 and PM-41).
+Note: The /CASL and /CASH pins are shortcut with each other on the mainboard,
+both wired to the /CAS pin of the SPU (ie. always accessing 16bit data at
+once).
+Note: The TSOP-II package (18mm length, super-flat and with spacing between pin
+10/11 and 30/31) is used on PU-23 boards. The pinouts and connections are
+identical for SOJ and TSOP-II.
+Note: Nippon Steels NN514256-series is normally 256Kx4bit, nethertheless, for
+some bizarre reason, their 256Kx16bit chip is marked "NN514256ALTT"... maybe
+that happened accidently in the manufacturing process.
+Note: The PM-41(2) board has on-chip RAM in the SPU (no external memory chip).
+
+IC303 - CDROM Buffer (32Kbyte)
+"HM62W256LFP-7T" (SRAM 32Kx8) (PCB bottom side) (PU-8)
+"SONY CXK5V8257BTM" 32Kx8 SRAM (PU-18)
+ 1-A14 4-A6 7-A3 10-A0 13-D2 16-D4 19-D7 22-/OE 25-A8 28-VCC
+ 2-A12 5-A5 8-A2 11-D0 14-GND 17-D5 20-/CS 23-A11 26-A13
+ 3-A7 6-A4 9-A1 12-D1 15-D3 18-D6 21-A10 24-A9 27-/WE
+Used only on older boards (eg. PU-8, PU-18), newer boards seem to have that RAM
+included in the 208pin SPU chip.
+
+IC201 - GPU-RAM (1MByte) (or 2MByte, of which, only 1MByte is used though)
+Samsung KM4132G271BQ-10 (128K x 32bit x 2 Banks, Synchronous Graphic RAM) 1MB
+Samsung K4G163222A-PC70 (256K x 32bit x 2 Banks, Synchronous Graphic RAM) 2MB
+ 1-DQ3 13-DQ19 25-/WE 37-N.C 49-A6 61-DQ9 73-VDDQ 85-VSS 97-DQ0
+ 2-VDDQ 14-VDDQ 26-/CAS 38-N.C 50-A7 62-VSSQ 74-DQ24 86-N.C 98-DQ1
+ 3-DQ4 15-VDD 27-/RAS 39-N.C 51-A8 63-DQ10 75-DQ25 87-N.C 99-VSSQ
+ 4-DQ5 16-VSS 28-/CS 40-N.C 52-N.C 64-DQ11 76-VSSQ 88-N.C 100-DQ2
+ 5-VSSQ 17-DQ20 29-A9(BA) 41-N.C 53-DSF 65-VDD 77-DQ26 89-N.C
+ 6-DQ6 18-DQ21 30-NC(GND) 42-N.C 54-CKE 66-VSS 78-DQ27 90-N.C
+ 7-DQ7 19-VSSQ 31-A0 43-N.C 55-CLK 67-VDDQ 79-VDDQ 91-N.C
+ 8-VDDQ 20-DQ22 32-A1 44-N.C 56-DQM1 68-DQ12 80-DQ28 92-N.C
+ 9-DQ16 21-DQ23 33-A2 45-N.C 57-DQM3 69-DQ13 81-DQ29 93-N.C
+ 10-DQ17 22-VDDQ 34-A3 46-VSS 58-NC 70-VSSQ 82-VSSQ 94-N.C
+ 11-VSSQ 23-DQM0 35-VDD 47-A4 59-VDDQ 71-DQ14 83-DQ30 95-N.C
+ 12-DQ18 24-DQM2 36-N.C 48-A5 60-DQ8 72-DQ15 84-DQ31 96-VDD
+Newer boards often have 2MB VRAM installed (of which only 1MB is used,
+apparently the 2MB chips became cheaper than the 1MB chips). At the chip side,
+the only difference is that Pin30 became an additional address line (that,
+called A8, and, accordingly, the old A8,A9 pins were renamed to A9,A10). At the
+mainboard side, the connection is exactly the same for both 1MB and 2MB chips;
+Pin30 is grounded on both PU-23 boards (which typically have 1MB) and PM-41
+boards (which typically have 2MB).
+Note: The PM-41(2) board has on-chip RAM in the GPU (no external memory chip).
+
+Pinouts - CLK Pinouts
+---------------------
+
+The "should-be" CPU clock is 33.868800 Hz (ie. the 44100Hz CDROM/Audio clock,
+multiplied by 300h). However, the different PSX/PSone boards are using
+different oscillators, multipliers and dividers, which aren't exactly reaching
+that "should-be" value. The PSone are using a single oscillator for producing
+CPU/GPU clocks, and for producing the TV/color signal:
+ For PAL, Fsc=4.43361875MHz (5^6*283.75Hz+25Hz) --> 4*Fsc=17.734MHz
+ For NTSC, Fsc=3.579545MHz (4.5*455/572 MHz) --> 4*Fsc=14.318MHz
+
+PSone/PAL - IC204 8pin - "CY2081, SL-509" or "2294A, 1913"
+Clock Multiplier/Divider
+ 1 53MHz ;17.734MHz*3 = 53.202 MHz (?)
+ 2 GND
+ 3 X1 17.734MHz
+ 4 X2 17.734MHz
+ 5 67MHz ;17.734MHz*3*2*7/11 = 67.711636 MHz (?)
+ 6 4.4Mhz ;17.734MHz/4 = 4.4335MHz (?) ;via 2K2 to IC502.pin15
+ 7 3.5V
+ 8 3.5V
+
+PSone/NTSC - IC204 8pin "CY2081 SL-500" (PSone, and PSX/PU-20 and up)
+Unknown. Uses a 14.318MHz oscillator, so multiply/divide factors must be
+somehow different.
+ 3*3*7*5/2/11 = 14.3181818
+ 3*3*7*7*100 = 44100
+The "optimal" conversion would be (hardware is barely able to do that):
+ 14.3181818 * 3*7*11*64 / (5*5*5*5*5) = 67.737600
+So, maybe it's doing
+ 14.3181818 * 2*2*13/11 ... or so?
+
+PSX/PAL
+PU-7 and PU-8 boards are using three separate oscillators:
+ X101: 67.737MHz (div2 = CPU Clock = 33.8685MHz) (div600h = 44.1kHz audio)
+ X201: 53.20MHz (GPU Clock) (div12 = PAL color clock)
+ X302: 4.000MHz (for CDROM SUB CPU)
+PU-18 does have same X101/X201 as above, but doesn't seem to have X302.
+
+PSX/NTSC
+PU-7 and PU-8 boards are using three separate oscillators:
+ X101: 67.737MHz (div2 = CPU Clock = 33.8685MHz) (div600h = 44.1kHz audio)
+ X201: 53.69MHz (GPU Clock) (div15 = NTSC color clock)
+ X302: 4.000MHz (for CDROM SUB CPU)
+PU-20 works more like PSone (a single oscillator, and CY2081 SL-500 divider)
+
+Pinouts - PWR Pinouts
+---------------------
+
+Voltage Summary
+ +7.5V Used to generate other voltages and CDROM/Joypad/MemoryCard/Expansion
+ +5.0V Used for Multiout, IC405, and IC502, and IC602
+ +3.5V Used for most ICs, and for Joypad/MemoryCard/Expansion
+ +3.48V Used for SPU and CDROM
+ GND Ground, shared for all voltages
+
+Fuses
+There are a lot of SMD elements marked FBnnn, these are NOT fuses (at least
+they don't seem to blow-up whatever you do). The actual fuses are marked PSnnn,
+found near the power switch and near the power socket.
+
+IC601 3pin +5.0V "78M05, RZ125, (ON)"
+ 1 +7.5V
+ 2 GND
+ 3 +5.0V (used for Multiout, IC405, and IC502)
+
+IC602 - Audio/CDROM Supply
+Called "LP29851MX-3.5" in service manual.
+ 1 VIN 5.0V (in)
+ 2 GND GND
+ 3 ON/OFF 5.0V (in)
+ 4 NOISE ?
+ 5 VOUT 3.48V (out)
+
+IC002/IC003 - Reset Generator (PM-41 board)
+ IC002 IC003 Expl.
+ 2 2 connected to Q002 (reset input?)
+ 5 5 connected via capacitor to GND
+ 6 1 reset-output (IC002=wired to /RES, IC003: via Q004 to /RES)
+ 7 - 7.5V
+ 4 3 GND
+ 1,3,8 4 NC
+/RES is connected via 330 ohm to GPU/CPU, and via 5K6 SPU/IC722/IC304.
+Note: Either IC002 or IC003/Q004 can be installed on PM-41 boards. Most or all
+boards seem to contain IC003/Q004.
+Note: PSX consoles have something similar on the Power Supply boards (IC101:
+M51957B).
+
+IC606/IC607 - TL594CD - Pulse-Width-Modulation Power-Control Chip
+ 1 1IN+
+ 2 1IN-
+ 3 FEEDBACK
+ 4 DTC
+ 5 CT
+ 6 RT
+ 7 GND
+ 8 C1
+ 9 E1
+ 10 E2
+ 11 C2
+ 12 VCC
+ 13 OUTPUT CTRL
+ 14 REF
+ 15 2IN-
+ 16 2IN+
+
+Q602
+ x +7.5V
+ y +3.5V
+ z REG
+
+CN602 - PU-8, PU-9 board Power Socket (to internal power supply board)
+ 1 Brown 7.5V (actually 7.69V)
+ 2 Red GND Ground
+ 3 Orange 3.5V (actually 3.48V)
+ 4 Yellow GND Ground
+ 5 White STAND-BY (3.54V, always ON, even if power switch is off)
+ 6 Blue GND Ground
+ 7 Magenta /RES Reset input (from power-on logic and reset button)
+Purpose of the standy-by voltage is unknown... maybe to expansion port?
+
+CN602 - PU-18, PU-23 board Power Socket (to internal power supply board)
+ 1 Brown 7.5V (actually 7.92V or so) (ie. higher than in PSone)
+ 2 Red GND Ground
+ 3 Orange 3.5V (actually 3.53V or so) (ie. quite same as PSone)
+ 4 Yellow GND Ground
+ 5 White /RES Reset input (from power-on logic and reset button)
+
+CN102 - Controller/memory card daughter-board connector (PU-23 board)
+ 1 /IRQ10 (/IRQ10)
+ 2 /ACK (/IRQ7)
+ 3 /JOY2
+ 4 7.5V (or actually 7.92V)
+ 5 /JOY1
+ 6 DAT
+ 7 GND
+ 8 CMD
+ 9 3.5V
+ 10 CLK
+
+Pinouts - Component List and Chipset Pin-Outs for Digital Joypad, SCPH-1080
+---------------------------------------------------------------------------
+
+Digital Joypad Component List (SCPH-1080)
+ Case: "SONY, CONTROLLER, Sony Computer Entertainment Inc. H"
+ Case: "SCPH-1080 Made in China"
+ PCB: "CMK-PIHB /\, CFS8121-200010-01"
+ U?: 32pin "(M), SC401800, FB C37B, JSJD520C" (Motorola) (TQFP-32 package)
+ U?: 14pin "BA10339F, 528 293" (Quad Comparator) (/ACK,JOYDAT,and reset or so)
+ X?: 3pin "4.00G1f" (on PCB bottom side)
+ Z1: 2pin z-diode or so (on PCB bottom side) (+1.7V VREF for BA10339F)
+ CN?: 7pin cable to controller port (plus shield; but not connected to PCB)
+ C1 2pin to GND and R5
+ C2 2pin capacitor for power supply input (between +3.5V and GND)
+ C3 2pin between BA.pin8 and (via R6) BA.pin15
+ R1 2pin 1M ohm (for X1)
+ R2 2pin 2.7K
+ R3 2pin 8xK ohm?
+ R4 2pin 100K
+ R5 2pin 22K ohm
+ R6 2pin 56K ohm
+ RN1 8pin 4x200 ohm (/JOYn,JOYCMD,JOYCLK)
+ RN2 8pin 4x22K ohm (pull-ups for button bit0..3)
+ RN3 8pin 4x22K ohm (pull-ups for button bit12..15)
+ RN4 8pin 4x22K ohm (pull-ups for button bit8..11)
+ RN5 8pin 4x22K ohm (pull-ups for button bit4..7)
+
+Digital Joypad Connection Cable:
+ PSX.1 -------brown---- PAD.2 JOYDAT
+ PSX.2 -------orange--- PAD.6 JOYCMD
+ PSX.3 --- NC +7.5V
+ PSX.4 -------black---- PAD.3 GND
+ PSX.5 -------red------ PAD.4 +3.5V
+ PSX.6 -------yellow--- PAD.5 /JOYn
+ PSX.7 -------blue----- PAD.7 JOYCLK
+ PSX.8 --- NC /IRQ10
+ PSX.9 -------green---- PAD.1 /ACK
+ PSX.Shield --shield--- NC (cable is shielded but isn't connected in
+joypad)
+
+Digital Joypad 32pin SC401800 Chip Pin-Outs
+ 1 Bit14 SW-X
+ 2 Bit13 SW-O
+ 3 Bit12 SW-/\
+ 4 Bit11 SW-R1 (via cable pin1, white wire)
+ 5 Bit10 SW-L1 (via cable pin1, white wire)
+ 6 Bit9 SW-R2 (via cable pin3, black wire)
+ 7 Bit8 SW-L2 (via cable pin3, black wire)
+ 8 via BA10339F.pin7 to cn.2 JOYDAT (PSX.1)
+ ---
+ 9 via RN1 (200 ohm) to cn.5 /JOYn (PSX.6)
+ 10 via RN1 (200 ohm) to cn.6 JOYCMD (PSX.2)
+ 11 via RN1 (200 ohm) to cn.7 JOYCLK (PSX.7)
+ 12 GND to cn.3 (PSX.4)
+ 13 Bit7 SW-LEFT
+ 14 Bit6 SW-DOWN
+ 15 Bit5 SW-RIGHT
+ 16 via BA10339F.pin5 to cn.1 /ACK (PSX.9)
+ ---
+ 17 Bit4 SW-UP
+ 18 Bit3 SW-START
+ 19 Bit2 (HI) (would be R3 on Analog Pads) ;\unused, but working button inputs
+ 20 Bit1 (HI) (would be L3 on Analog Pads) ;/(each fitted with a RN2 pullup)
+ 21 Bit0 SW-SELECT
+ 22
+ 23
+ 24 wired to SC401800.pin25
+ ---
+ 25 wired to SC401800.pin24
+ 26 4.00MHz'a
+ 27 4.00MHz'b
+ 28 +3.5V to cn.4 (PSX.5)
+ 29 wired to SC401800.pin32, and via 22K ohm to +3.5V, and to BA.14
+ 30
+ 31 Bit15 SW-[]
+ 32 wired to SC401800.pin29
+
+Digital Joypad 14pin BA10339F Chip Pin-Outs
+ 1 OUT2 CN.2 JOYDAT (PSX.1)
+ 2 OUT1 CN.1 /ACK (PSX.9)
+ 3 VCC +3.5V
+ 4 -IN1 +1.7V VREF via Z1 to GND
+ 5 +IN1 CXD.16 /ACK
+ 6 -IN2 +1.7V VREF via Z1 to GND
+ 7 +IN2 CXD.8 JOYDAT
+ ---
+ 8 -IN3 +1.7V VREF via Z1 to GND
+ 9 +IN3 C3,R3,R4
+ 10 -IN4 C1 to +3.5V
+ 11 +IN4 GND
+ 12 GND GND
+ 13 OUT4 NC ??
+ 14 OUT3 CXD.29/32
+
+Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1150
+--------------------------------------------------------------------------
+
+This applies for two controller versions:
+ SCPH-1150 Analog Pad with Single Rumble Motor (japan only)
+ SCPH-1180 Analog Pad without Rumble Motor
+Both are using the same PCB, and the same SD657 chip. The difference is that
+the motor, transistors, and some resistors aren't installed in SCPH-1180.
+
+Analog Joypad Component List (SCPH-1150, single motor)
+ Case "SONY, ANALOG, CONTROLLER, SonyCompEntInc. A, SCPH-1150 MADE IN CHINA"
+ PCB1 "DD1P09A" (mainboard with digital buttons)
+ PCB2 "DD1Q14A" (daughterboard with analog joysticks)
+ PCB3 "DD1Q15A-R" (daughterboard with R-1, R-2 buttons) (J3)
+ PCB4 "DD1Q15A-L" (daughterboard with L-1, L-2 buttons) (J2)
+ U1 42pin "SD657, 9702K3006" (2x21pins, L=17.8mm, W=7mm, W+Pins=11mm)
+ U2 3pin "DR, 4.Z"
+ Q1 3pin "BQ03" or so (motor post-amp)
+ Q2 3pin "S6","SG","9S" or so (motor pre-amp)
+ Y1 3pin "400CMA"
+ CN1 8pin cable to PSX controller port
+ CN2 8pin ribbon cable to analog-joystick daughterboard (not so robust cable)
+ J1 2pin wires to rumble motor (in left handle) (digital, on/off)
+ J2 3pin ribbon cable to L-1, L-2 button daughterboard
+ J3 3pin ribbon cable to R-1, R-2 button daughterboard
+ LED1 4pin red/green LED (optics without mirror)
+ D1,D2 diodes
+ plus resistors/capacitors
+
+Analog Joypad Connection Cables (SCPH-1150)
+CN1 (cable to PSX controller port) (same for SCPH-1150 and SCPH-1200)
+ PSX.1 -------brown---- PAD.2 JOYDAT
+ PSX.2 -------orange--- PAD.6 JOYCMD
+ PSX.3 -------magenta-- PAD.8 +7.5V
+ PSX.4 -------black---- PAD.3 GND
+ PSX.5 -------red------ PAD.4 +3.5V
+ PSX.6 -------yellow--- PAD.5 /JOYn
+ PSX.7 -------blue----- PAD.7 JOYCLK
+ PSX.8 --- NC /IRQ10
+ PSX.9 -------green---- PAD.1 /ACK
+ PSX.Shield --shield--- NC (cable is shielded but isn't connected in
+joypad)
+CN2 (ribbon cable to analog-joystick daughterboard) (SCPH-1150)
+ 8 +3.5V to POT pins
+ 7 Button L3 pins A,C
+ 6 GND to POT pins and Button L3/R3 pins B,D
+ 5 Button R3 pins A,C
+ 4 Axis R_Y middle POT pin (SD657.18)
+ 3 Axis R_X middle POT pin (SD657.17)
+ 2 Axis L_Y middle POT pin (SD657.16)
+ 1 Axis L_X middle POT pin (SD657.15)
+J3 (ribbon cable to R-1, R-2 button daughterboard) (SCPH-1150)
+ 1 (red) R1
+ 2 (gray) GND
+ 3 (gray) R2
+J2 (ribbon cable to L-1, L-2 button daughterboard) (SCPH-1150)
+ 1 (red) L1
+ 2 (gray) GND
+ 3 (gray) L2
+J1 wires to small rumble motor (SCPH-1150)
+ 1 (red) +7.5V
+ 2 (black) Q1
+
+Analog Joypad Chipset Pin-Outs (SCPH-1150)
+U1 42pin "SD657, 9702K3006"
+ 1 NC?
+ 2 NC?
+ 3 /RESET? (U2.3)
+ 4 OSC
+ 5 OSC
+ 6 BUTTON Bit3 START SW1
+ 7 BUTTON Bit2 R3 (via CN2.5)
+ 8 BUTTON Bit1 L3 (via CN2.7)
+ 9 BUTTON Bit0 SELECT SW3
+ 10 GND
+ 11 BUTTON Bit7 LEFT SW4
+ 12 BUTTON Bit6 DOWN SW5
+ 13 BUTTON Bit5 RIGHT SW6
+ 14 BUTTON Bit4 UP SW7
+ 15 Analog Axis L_X (via CN2.1)
+ 16 Analog Axis L_Y (via CN2.2)
+ 17 Analog Axis R_X (via CN2.3)
+ 18 Analog Axis R_Y (via CN2.4)
+ 19 NC?
+ 20 3.5V
+ 21 3.5V
+ ---
+ 22 BUTTON Bit15 [] SW11
+ 23 BUTTON Bit14 >< SW10
+ 24 BUTTON Bit13 () SW9
+ 25 BUTTON Bit11 R1 (via J3.1)
+ 26 BUTTON Bit12 /\ SW8
+ 27 BUTTON Bit10 L1 (via J3.1)
+ 28 BUTTON Bit9 R2 (via J3.3)
+ 29 BUTTON Bit8 L2 (via J3.3)
+ 30 PSX.2/CN1.6 JOYCMD orange (via 220 ohm R14)
+ 31 PSX.1/CN1.2.JOYDAT brown (via 22 ohm R13 and diode D2)
+ 32 PSX.7/CN1.7 JOYCLK blue (via 220 ohm R12)
+ 33 PSX.6/CN1.5./JOYn yellow (via 220 ohm R11)
+ 34 LED.GREEN (LED.4)
+ 35 LED.RED (LED.3)
+ 36 MOTOR (via 4.7Kohm R8 to Q2, then via Q1 to motor)
+ 37 NC?
+ 38 NC?
+ 39 PSX.9/CN1.1./ACK green (via 22 ohm R10)
+ 40 NC?
+ 41 MODE SW2 (analog button)
+ 42 GND
+U2 (probably reset signal related)
+ 1 from 3.5V (via R1,D1,R2)
+ 2 to U1.3 (/RESET?) (U2.rear contact = same as U2.pin2)
+ 3 GND
+Q1 "BQ03" or so (motor post-amp)
+ 1 Q2.2 (via 1Kohm R7)
+ 2 to Motor (-)
+ 3 GND
+Q2 "S6","SG","9S" or so (motor pre-amp)
+ 1 SD657.36 (via 4.7Kohm R8)
+ 2 Q1.1 (via 1Kohm R7) (and via 100Kohm R13 to GND)
+ 3 3.5V
+
+Motor
+Left/Single Motor (SCPH-1150)
+ 27.5mm Total Length (18.5mm Motor, 2mm Axis, 7mm Weight/block)
+ 12.0mm Width/Diameter (of Weight, and of Motor at flat side)
+
+Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1200
+--------------------------------------------------------------------------
+
+Analog Joypad Component List (SCPH-1200, two motors)
+ Case "SONY, ANALOG, CONTROLLER, SonyCompEntInc. H, SCPH-1200 MADE IN CHINA"
+ PCB1 "01, /\YG-H2, (r)RU" (mainboard with digital buttons)
+ PCB2 "M-29-01, YG-H3, (r)RU" (daughterboard with analog joysticks)
+ PCB3 "E, /\YG-H2, (r)RU, 01" (daughterboard with R-1, R-2 buttons) (J1)
+ PCB4 "01, W, /\YG-H2, (r)RU" (daughterboard with L-1, L-2 buttons) (J2)
+ U1 44pin "SONY, CXD8771Q 4A03, JAPAN 9840 HAL, 148896"
+ U2 4pin ",\\ 29" (PST9329) (System Reset with 2.9V detection voltage)
+ U3 8pin "2904, 8346G, JRC" (NJM2904) (Dual Operational Amplifier)
+ Q1 3pin ".Y S'" (big transistor for big M1 rumble motor)
+ Q2 3pin "Z" (small transistor for small M2 rumble motor)
+ Y1 3pin "800CMLX" or so (hides underneath of the CN2 ribbon cable)
+ CN1 8pin cable to PSX controller port
+ CN2 8pin ribbon cable to analog-joystick daughterboard
+ J1 3pin ribbon cable to R-1, R-2 button daughterboard
+ J2 3pin ribbon cable to L-1, L-2 button daughterboard
+ M1 2pin wires to left/big rumble motor (analog, slow/fast)
+ M2 2pin wires to right/small rumble motor (digital, on/off)
+ ZD1,ZD2 some Z-diodes
+ D1,D2 diodes near M1,M2 motors (these diodes aren't installed)
+ LED1 red analog mode LED (with transparent optics/light direction mirror)
+ plus resistors/capacitors
+
+Note: There's also a different SCPH-1200 revision, which having a smaller
+mainboard with analog joysticksonboard, plus a single sided PCB for the digital
+buttons (that is, similar to SCPH-110, but with the single sided PCB instead of
+membrane foil).
+
+Analog Joypad Connection Cables (SCPH-1200)
+CN1 (cable to PSX controller port) (same for SCPH-1150 and SCPH-1200)
+ PSX.1 -------brown---- PAD.2 JOYDAT
+ PSX.2 -------orange--- PAD.6 JOYCMD
+ PSX.3 -------magenta-- PAD.8 +7.5V
+ PSX.4 -------black---- PAD.3 GND
+ PSX.5 -------red------ PAD.4 +3.5V
+ PSX.6 -------yellow--- PAD.5 /JOYn
+ PSX.7 -------blue----- PAD.7 JOYCLK
+ PSX.8 --- NC /IRQ10
+ PSX.9 -------green---- PAD.1 /ACK
+ PSX.Shield --shield--- NC (cable is shielded but isn't connected in
+joypad)
+CN2 (ribbon cable to analog-joystick daughterboard) (SCPH-1200)
+ 1 +3.5V to POT pins
+ 2 Button L3 pins C,D
+ 3 GND to POT pins and Button L3/R3 pins A,B
+ 4 Button R3 pins C,D
+ 5 Axis R_Y middle POT pin (CXD.20)
+ 6 Axis R_X middle POT pin (CXD.19)
+ 7 Axis L_X middle POT pin (CXD.21)
+ 8 Axis L_Y middle POT pin (CXD.22)
+J1 (ribbon cable to R-1, R-2 button daughterboard) (SCPH-1200)
+ 1 (red) R1
+ 2 (gray) GND
+ 3 (gray) R2
+J2 (ribbon cable to L-1, L-2 button daughterboard) (SCPH-1200)
+ 1 (red) L1
+ 2 (gray) GND
+ 3 (gray) L2
+M1 wires to big rumble motor (SCPH-1200)
+ + (red) Q1.E
+ - (black) GND
+M2 wires to small rumble motor (SCPH-1200)
+ + (red) +7.5V
+ - (black) Q2.C
+
+Analog Joypad Chipset Pin-Outs (SCPH-1200)
+U1 SONY CXD8771Q
+ 1 PSX.7/CN1.7 JOYCLK (via 220 ohm R2)
+ 2 via R10 to U3.3 (for big M1 motor)
+ 3 via R15 to Q2.B (for small M2 motor)
+ 4 GND
+ 5 BUTTON Bit15 []
+ 6 BUTTON Bit14 ><
+ 7 BUTTON Bit13 ()
+ 8 BUTTON Bit12 /\
+ 9 BUTTON Bit11 R1 (via J1.1)
+ 10 BUTTON Bit10 L1 (via J2.1)
+ 11 BUTTON Bit9 R2 (via J1.3)
+ ---
+ 12 BUTTON Bit8 L2 (via J2.3)
+ 13 GND
+ 14 U2.Pin3 (reset)
+ 15 Y1'a
+ 16 Y1'b
+ 17 GND
+ 18 +3.5V
+ 19 Analog Axis R_X via CN2.6
+ 20 Analog Axis R_Y via CN2.5
+ 21 Analog Axis L_X via CN2.7
+ 22 Analog Axis L_Y via CN2.8
+ ---
+ 23 GND
+ 24 GND
+ 25 GND
+ 26 GND
+ 27 GND
+ 28 +3.5V
+ 29 BUTTON Bit0 SELECT
+ 30 BUTTON Bit1 L3 (via CN2.2)
+ 31 BUTTON Bit2 R3 (via CN2.4)
+ 32 BUTTON Bit3 START
+ 33 BUTTON Bit4 UP
+ ---
+ 34 BUTTON Bit5 RIGHT (aka spelled RIHGT on the PCB)
+ 35 BUTTON Bit6 DOWN
+ 36 BUTTON Bit7 LEFT
+ 37 PSX.6/CN1.5./JOYn (via 220 ohm R1)
+ 38 ANALOG BUTTON
+ 39 GND
+ 40 +3.5V
+ 41 /LED (to LED1, and from there via 300 ohm R6 to +3.5V)
+ 42 PSX.9/CN1.1./ACK (via 22 ohm R5)
+ 43 PSX.1/CN1.2.JOYDAT (via 22 ohm R3)
+ 44 PSX.2/CN1.6 JOYCMD (via 220 ohm R4)
+U2 PST9329 (System Reset with 2.9V detection voltage)
+ 1 NC GND
+ 2 GND GND
+ 3 Vout U1.14
+ 4 VCC +3.5V
+U3 NJM2904 (Dual Operational Amplifier)
+ 1 A.OUTPUT Q1.B (big motor M1 transistor)
+ 2 A.INPUT- to R11/R12
+ 3 A.INPUT+ to R10/R17
+ 4 GND PSX.4/CN1.3 GND
+ 5 B.INPUT+ GND
+ 6 B.INPUT- NC?
+ 7 B.OUTPUT NC?
+ 8 VCC PSX.3/CN1.8 +7.5V
+Q1 (transistor for big M1 motor)
+ E M1+
+ B U3.1 (NJM2904)
+ C +7.5V
+Q2 (transistor for small M2 motor)
+ E GND
+ B via 1K ohm R15 to U1.3 (CXD), and via 100K ohm R16 to GND
+ C M2-
+
+Motors
+ Left/Large Motor (SCPH-1200)
+ 24.0mm Total Length (12.0mm Motor, 2.5mm Axis, 9.5mm Weight/plates)
+ 24.0mm Diameter (Motor), 20.0mm Diameter (Weight/plates)
+ Right/Small Motor (SCPH-1200)
+ 25.4mm Total Length (18.7mm Motor, 2mm Axis, 4.7mm Weight/plates)
+ 12.0mm Width/Diameter (of Weight, and of Motor at flat side)
+
+Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-110
+-------------------------------------------------------------------------
+
+Analog Joypad Component List (SCPH-110, two motors, PSone-design)
+ Case "SONY, ANALOG CONTROLLER, SonyCompEntInc. A, SCPH-110 MADE IN CHINA"
+ PCB1 "SA1Q22A, <PF-LP>, KPC, 7694V-0" (mainboard with joysticks onboard)
+ PCB2 "..." (membrane/foil with digital buttons)
+ U1 44pin "SD707, 039 107"" (4x11pin)
+ Q1 3pin "KA" (big transistor for left/big M1 rumble motor)
+ Q2 3pin "LG" (small transistor for right/small M2 rumble motor)
+ D1 2pin diode (for large motor, reference Z-diode with pull-up?)
+ D2 3pin dual-diode (R5/IRQ7 to GND and R3/DAT to GND)
+ CN1 9pin cable to PSX controller port
+ J1 16pin ribbon cable from membrane/foil
+ M1 2pin wires to left/big rumble motor (analog, slow/fast)
+ M2 2pin wires to right/small rumble motor (digital, on/off)
+ LED1 2pin red analog mode LED (with long legs, without mirror/optics)
+ plus resistors/capacitors
+
+Analog Joypad Connection Cables (SCPH-110)
+CN1 (cable to PSX controller port)
+ 1 +3.5V (logic supply)
+ 2 GND3 (logic supply)
+ 3 /IRQ7
+ 4 /SEL
+ 5 CMD
+ 6 DAT
+ 7 CLK
+ 8 GND7 (motor supply)
+ 9 +7.5V (motor supply)
+J1 (ribbon cable with membrane/foil with digital buttons)
+ 1 BUTTON Bit8 L2
+ 2 BUTTON Bit10 L1
+ 3 BUTTON Bit4 UP
+ 4 BUTTON Bit5 RIGHT
+ 5 BUTTON Bit6 DOWN
+ 6 BUTTON Bit7 LEFT
+ 7 GND3
+ 8 ANALOG BUTTON
+ 9 BUTTON Bit0 SELECT
+ 10 BUTTON Bit3 START
+ 11 BUTTON Bit15 SQUARE []
+ 12 BUTTON Bit14 CROSS ><
+ 13 BUTTON Bit13 CIRCLE ()
+ 14 BUTTON Bit12 TRIANGLE /\
+ 15 BUTTON Bit11 R1
+ 16 BUTTON Bit9 R2
+M1 wires to left/big rumble motor (SCPH-110)
+ 1 (red) Q1
+ 2 (black) GND (via some ohm)
+M2 wires to right/small rumble motor (SCPH-110)
+ 1 (red) +7.5V
+ 2 (black) Q2
+
+U1 ("SD707, 039 107")
+ 1 via R9/Q2 to M2 (right/small) (digital 0V=off, 3V=on)
+ 2 via "JP1" to LED (330 ohm)
+ 3 +3.5V
+ 4 BUTTON Bit2 R3
+ 5 vr2 RX (lt/rt)
+ 6 vr1 RY (up/dn)
+ 7 vr4 LX (lt/rt)
+ 8 vr3 LY (up/dn)
+ 9 BUTTON Bit1 L3
+ 10 GND3
+ 11 GND7
+ ---
+ 12 via Q1 to M1 (left/large) (1V=off, 6V=fast)
+ 13 via D1/R7 to M1 (left/large) (6.7V)
+ 14 +7.5V
+ 15 +7.5V
+ 16 BUTTON Bit8 L2
+ 17 BUTTON Bit10 L1
+ 18 BUTTON Bit4 UP
+ 19 BUTTON Bit5 RIGHT
+ 20 BUTTON Bit6 DOWN
+ 21 BUTTON Bit7 LEFT
+ 22 GND3
+ ---
+ 23 BUTTON Bit9 R2
+ 24 BUTTON Bit11 R1
+ 25 BUTTON Bit12 TRIANGLE /\
+ 26 BUTTON Bit13 CIRCLE ()
+ 27 BUTTON Bit14 CROSS ><
+ 28 BUTTON Bit15 SQUARE []
+ 29 BUTTON Bit3 START
+ 30 BUTTON Bit0 SELECT
+ 31 ANALOG BUTTON
+ 32 NC
+ 33 +3.5V
+ ---
+ 34 GND3
+ 35 NC
+ 36 via R5 to /IRQ7
+ 37 via R1 to /SEL
+ 38 via R4 to CMD
+ 39 via R3 to DAT
+ 40 via R2 to CLK
+ 41 +7.5V
+ 42 +7.5V
+ 43 GND7
+ 44 GND7
+
+Misc
+VR1..VR4 -- analog inputs
+R1..R5 -- signals to/from psx
+R6 ?
+R7 M1
+R8
+R9
+R10
+JP1
+C1 3.5V to GND3 (22uF)
+C2 3.5V to GND3 (U1)
+C3 VR1 to GND3
+C4 VR2 to GND3
+C5 VR3 to GND3
+C6 VR4 to GND3
+C7 M2+ to M2-
+C8 M1+ to M1-
+C9 M1 related
+S5
+S6
+
+Motors
+ Left/Large Motor (SCPH-110)
+ 23.0mm Total Length (12.0mm Motor, 3mm Axis, 8.0mm Weight/plates)
+ 24.0mm Diameter (Motor), 20.0mm Diameter (Weight/plates)
+ Right/Small Motor (SCPH-110)
+ 25.4mm Total Length (18.7mm Motor, 2mm Axis, 4.7mm Weight/plates)
+ 12.0mm Width/Diameter (of Weight, and of Motor at flat side)
+
+ M1+ --o---Q1---o--------- U1.12
+ | | | analog
+ Left | | C9
+ Large | | |
+ | o----o--------- 7.5V
+ | |
+ C8 R7
+ | D1 | 6.7V
+ o---|>|--o--------- U1.13
+ |
+ M1- --o------------------ GND7
+
+D1 is probably a Z-diode with R7 as pull-up, creating a reference/source
+voltage at U1.13 for the analog output at U1.12.
+
+ M2+ --o------------------ 7.5V
+ |
+ Right | o-------o--R9-- U1.1
+ Small | | | on/off
+ C7 | R10
+ | | |
+ M2- --o---Q2------o------ GND7
+ ___ ___ ____
+ axis | | / \ \
+ __/___ ______| m | __.____________|__. | |
+ /__/__/ | | w | | | | ' | | axis | ' | |
+ | |/ weight |___| |___| \___/_/ \___/____/
+ \____/ weight motor
+
+Pinouts - Component List and Chipset Pin-Outs for Dualshock2, SCPH-10010
+------------------------------------------------------------------------
+
+Dualshock2 Component List
+PCB "SA1P07A, >PF-LP<, HCMK-P3X, 9 RU"
+Foil "9, SA1Q28B, 237T1, 3 S"
+ U1 8pin "358, 937" (LM358, dual op-amp)
+ Ux 44pin "9950KP003, SD718A" (whatever microprocessor)
+ U3 16pin "HC, 4051A, 941" (74HC4051A, 8-to-1 analog mux)
+ U4 16pin "HC, 4051A, 941" (74HC4051A, 8-to-1 analog mux)
+ U5 4pin "CUJ" (reset detection?)
+ Y1 3pin "400G945" (ceramic resonator)
+ Q1 3pin driver for motor M1 (with large weight; input from U1 op-amp)
+ Q5 3pin driver for motor M2 (with small weight; input directly from CPU)
+ Q6 3pin driver for button [], X
+ Q7 6pin driver for button DPAD.LT, DPAD.RT
+ Q8 6pin driver for button R1, R2, /\, O
+ Q9 3pin driver for button L1, L2
+ Q10 6pin driver for button DPAD.UP, DPAD.DN
+ D3 3pin dual-diode (GND to .. and JOYDAT) (CN3.2 to CN3.3 and CN3.4)
+ D5 2pin (not installed) (GND to VCC 3.5V) (CN3.2 to CN3.1)
+ D6 2pin (not installed) (AGND to AVCC 7.5V) (CN3.8 to CN3.9)
+ D7 2pin (not installed) (GND to JOYCLK) (CN3.2 to CN3.7)
+ LED1 2pin Analog LED (red)
+ VR4 3pin analog joystick RY potentiometer
+ VR5 3pin analog joystick RX potentiometer
+ VR6 3pin analog joystick LY potentiometer
+ VR7 3pin analog joystick LX potentiometer
+ S1 4pin digital button R3
+ S2 4pin digital button L3
+ CN1 16pin Ribbon/foil (left half)
+ CN2 16pin Ribbon/foil (right half)
+ CN3 9pin Cable to controller connector
+ M1 2pin Left Motor with large weight (wire1=red, wire2=black)
+ M2 2pin Right Motor with small weight (wire1=white, wire2=black)
+ R1..R28 resistors (plus additional resistors printed on the foil)
+ C1..C14 capacitors
+
+Analog Buttons
+The foil contains printed resistors (large 19K ohm pull-down resistors, and
+small 7.6K ohm pull-up resistors). The pull-downs can get shorted by pressing a
+conductive piece of rubber against it:
+ ____________
+ | | ____________
+ '. .' | | ____________
+ '--____--' '. .' | | <-- rubber
+ '--____--' '.__________.'
+ .############.###. .############.###. .############.###. <-- resistors
+ no contact some contact full contact
+There are some oddities: The microprocessor has only two ADC inputs (the PCB
+contains analog multiplexors to map the currently selected signals to the ADC
+inputs). And, the pull-downs are GNDed via transistors instead of being
+directly wired to GND (that is used to share DPAD inputs, and may also reduce
+power consumption during inactivity).
+ .############. .############.###. .############.###. <-- resistor
+ | DPAD.LT | | DPAD.RT | | | NON-DPAD | |
+ | '------ | -----------+ | | | |
+ | | | | | | |
+ Q--. Q--. .--MUX | Q--. .--MUX |
+ | | | | | | | | | | | |
+ GND EN GND EN SEL ADC VCC GND EN SEL ADC VCC
+There is only one MUX and one pull-up shared for DPAD LT/RT (and same for
+DPAD.UP/DN). Shared access is done by activating only one of the pull-down
+transistors (that should work reliably even if it were mechanically possible to
+push LT/RT simultaneously).
+
+CN1 (foil, left half)
+ 1 button L2
+ 2 button L1
+ 3 button L1 and resistor U3.5
+ 4 button DPAD.LT
+ 5 button DPAD.LT, DPAD.RT and resistor? U3.4
+ 6 button DPAD.RT
+ 7 button DPAD.UP
+ 8 button DPAD.UP, DPAD.DN and resistor? U3.13
+ 9 button DPAD.DN
+ 10 VCC (to resistors)
+ 11 NC on foil
+ 12 button L2 and resistor U3.12
+ 13 button SELECT
+ 14 GND (for SELECT, ANALOG, START)
+ 15 button ANALOG
+ 16 NC on foil
+
+CN2 (foil, right half)
+ 1 button START
+ 2 button R2 and resistor U3.14
+ 3 NC on foil
+ 4 VCC (to resistors)
+ 5 NC on foil
+ 6 button [] and resistor U4.15
+ 7 button []
+ 8 button X and resistor U4.14
+ 9 button X
+ 10 button O and resistor U4.13
+ 11 button O
+ 12 button /\ and resistor U4.12
+ 13 button /\
+ 14 button R1 and resistor U3.15
+ 15 button R1
+ 16 button R2
+
+CN3 (cable to controller plug)
+ 1 red VCC 3.5V (PSX.5 4ohm)
+ 2 black GND (PSX.4 3ohm)
+ 3 green /JOYACK (PSX.9 4ohm)
+ 4 brown JOYDAT (PSX.1 4ohm)
+ 5 orange JOYCMD (PSX.2 4ohm)
+ 6 yellow /JOYn (PSX.6 4ohm)
+ 7 blue JOYCLK (PSX.7 4ohm)
+ 8 gray Motor AGND (PSX.4 3ohm)
+ 9 purple Motor AVCC 7.5V (PSX.3 4ohm)
+ - N/A /IRQ10 (PSX.8 none)
+GND and AGND have separate wires with 3 ohm each (so there's about 6 ohm
+between GND and AGND).
+
+VR4,VR5,VR6,VR7 (potentiometers for analog joysticks)
+ 1 GND
+ 2 POT (to U4 pin 5,4,1,2 for VR4,VR5,VR6,VR7)
+ 3 STICKSEL (Ux.10)
+
+U1 (LM358, dual op-amp)
+ 1 1OUT NC?
+ 2 1IN- NC?
+ 3 1IN+ Digital GND (CN3.2 black)
+ 4 GND Motor AGND (CN3.8 gray)
+ 5 2IN+ via R1 to Ux.26 and via C3 to GND
+ 6 2IN- via R3 and via R4
+ 7 2OUT to Q1 lower left
+ 8 VCC Motor AVCC 7.5V (CN3.9 purple)
+
+Ux (whatever microprocessor)
+ 1 CN2.1 button START
+ 2 CN1.13 button ANALOG
+ 3 U3.11 (mux sel0)
+ 4 U3.10 (mux sel1)
+ 5 U3.9 (mux sel2)
+ 6 Q6 lower left to CN2.7+9
+ 7 S2 digital button L3
+ 8 CN1.13 button SELECT
+ 9 VCC
+ 10 STICKSEL (to VR4,VR5,VR6,VR7)
+ 11 U3.3 (mux signal)
+ ---
+ 12 U4.3 (mux signal)
+ 13 GND
+ 14 GND
+ 15 GND
+ 16 S1 digital button R3
+ 17 MOTOR2 (via 1Kohm/R20 to Q5 motor M2)
+ 18 GND
+ 19 VCC
+ 20 LED (via 330ohm/R5 to LED1-)
+ 21 ?
+ 22 /JOYACK (via 22ohm/R15 to CN3.3 green)
+ ---
+ 23 JOYDAT (via 22ohm/R18 to CN3.4 brown)
+ 24 JOYCLK (via 220ohm/R19 to CN3.7 blue)
+ 25 JOYCMD (via 220ohm/R17 to CN3.5 orange)
+ 26 MOTOR1 (via R1 to U1.5 and via R2 to GND)
+ 27 /JOYn (via 220ohm/R16 to CN3.6 yellow)
+ 28 GND
+ 29 VCC
+ 30 OSC (from Y1)
+ 31 OSC' (from Y1)
+ 32 GND
+ 33 VCC
+ ---
+ 34 via 220ohm/R27 to U5.1
+ 35 via R26 to ... U5.1
+ 36 via R25 to ... U5.1
+ 37 to Q8.3
+ 38 to Q8.5
+ 39 to Q9
+ 40 to Q7.3 and Q10.3
+ 41 to Q7.5 and Q10.5
+ 42 U4.9 (mux sel2)
+ 43 U4.10 (mux sel1)
+ 44 U4.11 (mux sel0)
+
+U3 (74HC4051, 8-to-1 mux)
+ 1 X4 NC? NC?
+ 2 X6 NC? NC?
+ 3 Y to Ux.11 CPU analog input
+ 4 X7 from CN1.5 button DPAD.LT and DPAD.RT
+ 5 X5 from CN1.3 button L1
+ 6 /EN GND enable
+ 7 VEE GND ground'
+ 8 GND GND ground
+ 9 S2 from Ux.5 sel2
+ 10 S1 from Ux.4 sel1
+ 11 S0 from Ux.3 sel0
+ 12 X3 from CN1.12 button L2
+ 13 X0 from CN1.8 button DPAD.UP and DPAD.DN
+ 14 X1 from CN2.2 button R2
+ 15 X2 from CN2.14 button R1
+ 16 VCC VCC supply
+
+U4 (74HC4051, 8-to-1 mux)
+ 1 X4 from VR6.2 analog joystick LY
+ 2 X6 from VR7.2 analog joystick LX
+ 3 Y to Ux.12 CPU analog input
+ 4 X7 from VR5.2 analog joystick RX
+ 5 X5 from VR4.2 analog joystick RY
+ 6 /EN GND enable
+ 7 VEE GND ground'
+ 8 GND GND ground
+ 9 S2 from Ux. sel2
+ 10 S1 from Ux. sel1
+ 11 S0 from Ux. sel0
+ 12 X3 from CN2.12 button /\
+ 13 X0 from CN2.10 button O
+ 14 X1 from CN2.8 button X
+ 15 X2 from CN2.6 button []
+ 16 VCC VCC supply
+
+U5 (reset detection?)
+ 1 via 220ohm/R27 to Ux.34, and via R25 to Ux.36
+ 2 VCC
+ 3 via 1.3Kohm/R24 to U5.1
+ 4 NC?
+
+Q1
+ x from U1.7 (op-amp)
+ x supply AVCC 7.5V (CN3.9 purple)
+ x to motor M1.1 (with large weight)
+
+Q5
+ x via 1Kohm/R20 from Ux.17
+ x to motor M2.2 (with small weight)
+ x supply AGND 7.5V (CN3.8 gray)
+
+Q6
+ x from Ux.6
+ x to to CN2.7 (button []) and CN2.9 (button X)
+ x GND
+
+Q7
+ 1 GND
+ 2 GND
+ 3 from Ux.40
+ 4 to CN1.6 (button DPAD.RT)
+ 5 from Ux.41
+ 6 to CN1.4 (button DPAD.LT)
+
+Q8
+ 1 GND
+ 2 GND
+ 3 from Ux.37
+ 4 to CN2.15 (button R1) and CN2.16 (button R2)
+ 5 from Ux.38
+ 6 to CN2.11 (button O) and CN2.13 (button /\)
+
+Q9
+ x from Ux.39
+ x to CN1.1 (button L2) and CN1.2 (button L1)
+ x GND
+
+Q10
+ 1 GND
+ 2 GND
+ 3 from Ux.40
+ 4 to CN1.7 (button DPAD.UP)
+ 5 from Ux.41
+ 6 to CN1.9 (button DPAD.DN)
+
+Pinouts - Component List and Chipset Pin-Outs for Namco Lightgun, NPC-103
+-------------------------------------------------------------------------
+
+Schematic
+http://www.nicolaselectronics.be/reverse-engineering-the-playstation-g-con45/
+
+Namco Lightgun "NPC-103, (C) 1996 NAMCO LTD." Component List
+PCB "DNP-0500A, NPC10300, namco, CMK-P3X"
+ U1 44pin "NAMCO103P, 1611U1263, JAPAN 9847EAI, D0489AAF"
+ U2 8pin "7071, 8C19" (=BA7071F, Sync Separator IC with AFC)
+ XTAL 2pin "CSA 8.00WT"
+ PS1 3pin Light sensor with metal shielding
+ J1 9pin Connector for 9pin cable to PSX controller and GunCon plugs
+ plus resistors and capacitors, and A1,A2,B1,B2,T1,T2 wires to buttons
+PCB "DN-P-0501"
+ DIP Button (with black T1,T2 wires) (trigger)
+PCB "DN-P-0502"
+ Button A (with red A1,A2 wires) (left side)
+ Button B (with white B1,B2 wires) (right side)
+Other Components
+ Lens (20mm)
+Cable Pinouts
+ J1.Pin1 green PSX.Controller.Pin5 +3.5V
+ J1.Pin2 brown PSX.Controller.Pin4 GND
+ J1.Pin3 black PSX.Controller.Pin9 /ACK/IRQ7
+ J1.Pin4 red PSX.Controller.Pin6 /JOYn
+ J1.Pin5 yellow PSX.Controller.Pin1 JOYDAT
+ J1.Pin6 orange PSX.Controller.Pin2 JOYCMD
+ J1.Pin7 blue PSX.Controller.Pin7 JOYCLK
+ J1.Pin8 gray GunCon shield (GND)
+ J1.Pin9 white GunCon composite video
+ N/A PSX.Controller.Pin3 +7.5V
+ N/A PSX.Controller.Pin8 /IRQ10
+ N/A PSX.Controller Shield
+U1 "NAMCO103P" Pinouts (44pin, arranged as 4x11pin)
+ 1 GND 12 SYNC (from U2) 23 3.5V 34 SW1 (A)
+ 2 GND 13 3.5V 24 3.5V 35 3.5V
+ 3 GND 14 3.5V 25 3.5V 36 3.5V
+ 4 GND 15 SW3 (TRIGGER) 26 GND 37 SW2 (B)
+ 5 GND 16 JOYCLK (J1.Pin7 via 220 ohm R7) 27 GND 38 3.5V
+ 6 GND 17 3.5V 28 GND 39 3.5V
+ 7 GND 18 JOYCMD (J1.Pin6 via 220 ohm R8) 29 GND 40 LIGHT (from PS1)
+ 8 GND 19 JOYDAT (J1.Pin5 via 0 ohm R10) 30 - 41 GND
+ 9 - 20 /JOYn (J1.Pin4 via 220 ohm R9) 31 GND 42 GND
+ 10 GND 21 /ACK/IRQ7 (J1.Pin3 via 0 ohm R11) 32 GND 43 OSC 8MHz
+ 11 GND 22 GND 33 GND 44 OSC 8MHz
+U2 "7071" Pinouts (=BA7071F, Sync Separator IC with AFC) (2x4pin)
+ 1 VIN = SYNC.IN from J1.Pin9 Composite Video (via C5/C6/C7/R6)
+ 2 HD_OUT = NC
+ 3 GND = GND
+ 4 PD_OUT = NC
+ 5 HOSC_R = via 100K to GND
+ 6 VCC = 3.5V
+ 7 VD_OUT = NC
+ 8 SYNC_OUT = SYNC.OUT to U1.pin12 (with R4 pull-up)
+
+Pinouts - Component List and Chipset Pin-Outs for Multitap, SCPH-1070
+---------------------------------------------------------------------
+
+Multitap Component List
+ Case "SONY, MULTITAP, SonyComputerEntertainmentInc, SCPH-1070 MADE IN CHINA"
+ PCB1 "SONY 1-659-343-11" (mainboard with Slot A,B, ICs, X1, PSX-cable)
+ PCB2 "SONY 1-711-414-11" (daughterboard with Slot C,D)
+ IC? 64pin "SONY JAPAN, CXD103, -166Q, 550D66E" (smd/back side)
+ IC02 8pin "7W14, 5K" some tiny SMD chip (for JOYCLK) (smd/back side)
+ X1 2pin "4.00G CMj" oscillator (front side)
+ J34 2pin fuse or 1 ohm resistor or so (for +3.5V input) (front side)
+ Jxx 2pin normal wire bridges (except: J34 is NOT a wire) (front side)
+Cables from Multitap PCB1 to PCB2:
+ 1pin black wire Shield/GND (lower edge)
+ 1pin black wire Shield/GND (upper edge)
+ 2x8pin red/gray ribbon cable (side edge)
+ 2x2pin red/gray ribbon cable (lower edge)
+ 2pin red/gray ribbon cable (upper middle) (gray=+3.3V, red=+7.5V)
+plus a bunch of SMD capacitors and around 70 SMD resistors.
+
+Multitap PSX Controller Port Cable
+ PSX.1 -------brown------ TAP.1 JOYDAT ;via 47 ohm (R57) to CXD.35
+ PSX.2 -------orange----- TAP.2 JOYCMD ;via 220 ohm (R58) to CXD.37
+ PSX.3 -------magenta---- TAP.3 +7.5V ;directly to +7.5V on JOY/CARD's
+ PSX.4 -------black------ TAP.4 GND ;directly to GND
+ PSX.5 -------red-------- TAP.5 +3.5V ;via 1 ohm or so (J34) to +3.3V
+ PSX.6 -------yellow----- TAP.6 /JOYn ;via 220 ohm (R59) to CXD.46
+ PSX.7 -------blue------- TAP.7 JOYCLK ;via 220 ohm (R60) to IC02.pin6
+ PSX.8 -------gray------- TAP.8 /IRQ10 ;via 47 ohm (R02/R16/R30/R44) to JOY's
+ PSX.9 -------green------ TAP.9 /ACK ;via 47 ohm (R61) to CXD.51
+ PSX.Shield --shield----- TAP.shielding.plate (GND)
+
+Multitap CARD A/B/C/D Slots
+ 1 JOYDAT Via 47 ohm (R11/R25/R38/R5x) to CXD.18/29/60/5 (and to JOY slot)
+ 2 JOYCMD Via 220 ohm (R10/R24/R39/R52) to CXD.19/30/62/6
+ 3 +7.5V Directly to PSX.3
+ 4 GND Directly to PSX.4
+ 5 +3.3V Via J34 to PSX.5 (+3.5V)
+ 6 /JOYn Via 220 ohm (R09/R2x/Rxx/R51) to CXD.11/22/52/61
+ 7 JOYCLK Via 220 ohm (R08/R2x/Rxx/R50) to CXD.33/33/47/47
+ 9 /ACK Via 47 ohm (R07/R2x/Rxx/R49) to CXD.12/21/45/64
+
+Multitap JOY A/B/C/D Slots
+ 1 JOYDAT Via 47 ohm (R06/Rxx/R34/R5x) to CXD.18/29/60/5 (and to CARD slot)
+ 2 JOYCMD Via 220 ohm (R05/R19/R35/R5x) to CXD.17/28/59/4
+ 3 +7.5V Directly to PSX.3
+ 4 GND Directly to PSX.4
+ 5 +3.3V Via 1 ohm or so (J34) to PSX.5 (+3.5V)
+ 6 /JOYn Via 220 ohm (R04/R18/R32/R4x) to CXD.16/20/55/63
+ 7 JOYCLK Via 220 ohm (R03/R17/R31/R45) to CXD.15/23/56/2
+ 8 /IRQ10 Via 47 ohm (R02/R16/R30/R44) to PSX.8
+ 9 /ACK Via 47 ohm (R01/R15/R29/R43) to CXD.13/27/54/7
+ Shield Directly to Shield/GND
+
+Multitap IC02 8pin "7W14, 5K" some tiny SMD chip
+ 1
+ 2
+ 3
+ 4 GND
+ 5
+ 6 via 220 ohm (R60) to PSX.7 (JOYCLK)
+ 7 to CXD.Pin48
+ 8 +3.3V, aka via 1 ohm (J34) to PSX.5 (+3.5V)
+
+Multitap "SONY CXD103-166Q" Chip Pin-Outs (Multitap CPU)
+ 1 via to 10K (R63) to +3.3V, and via C13 to GND (probably power-on reset)
+ 2 JOY.D.7.JOYCLK
+ 3
+ 4 JOY.D.2.JOYCMD
+ 5 JOY/CARD.D.1.JOYDAT
+ 6 CARD.D.2.JOYCMD
+ 7 JOY.D.9./ACK
+ 8 4MHz X1/C12
+ 9 4MHz X1/C11
+ 10 GND
+ 11 CARD.A.6./JOYn
+ 12 CARD.A.9./ACK
+ 13 JOY.A.9./ACK
+ 14
+ 15 JOY.A.7.JOYCLK
+ 16 JOY.A.6./JOYn
+ 17 JOY.A.2.JOYCMD
+ 18 JOY/CARD.A.1.JOYDAT
+ 19 CARD.A.2.JOYCMD
+ ---
+ 20 JOY.B.6./JOYn
+ 21 CARD.B.9./ACK
+ 22 CARD.B.6./JOYn
+ 23 JOY.B.7.JOYCLK
+ 24
+ 25 GND
+ 26 +3.3V
+ 27 JOY.B.9./ACK
+ 28 JOY.B.2.JOYCMD
+ 29 JOY/CARD.B.1.JOYDAT
+ 30 CARD.B.2.JOYCMD
+ 31 GND
+ 32
+ ---
+ 33 CARD.A/B.7.JOYCLK
+ 34
+ 35 PSX.1.JOYDAT
+ 36
+ 37 PSX.2.JOYCMD
+ 38
+ 39
+ 40
+ 41
+ 42 GND
+ 43
+ 44 GND
+ 45 CARD.C.9./ACK
+ 46 PSX.6./JOYn
+ 47 CARD.C/D.7.JOYCLK
+ 48 IC02.Pin7.PSX.JOYCLK
+ 49
+ 50
+ 51 PSX.9./ACK
+ ---
+ 52 CARD.C.6./JOYn
+ 53
+ 54 JOY.C.9./ACK
+ 55 JOY.C.6./JOYn
+ 56 JOY.C.7.JOYCLK
+ 57 GND
+ 58 +3.3V
+ 59 JOY.C.2.JOYCMD
+ 60 JOY/CARD.C.1.JOYDAT
+ 61 CARD.D.6./JOYn
+ 62 CARD.C.2.JOYCMD
+ 63 JOY.D.6./JOYn
+ 64 CARD.D.9./ACK
+
+Pinouts - Memory Cards
+----------------------
+
+Sony Playstation Memory Card (SCPH-1020)
+The "SONY CXD8732AQ" chip is installed on memory cards with "SPC02K1020B"
+boards, however, the text layer on the board says that it's an "LC86F8604A"
+chip. So, the CXD8732AQ is most probably a standard LC86F8604A chip (more on
+that below) with a Sony Memory Card BIOS ROM on it.
+The "SONY CXD8732AQ" comes in a huge 64pin package, but it connects only to:
+ 5 = /IRQ7 (via 22 ohm) 2 = /RESET (from U2)
+ 6 = JOYCLK (via 220 ohm) 30,31 = CF1,CF2 (12 clock pulses per 2us)
+ 7 = /JOYn (via 220 ohm) 14,16,25,32,38,39,61 = 3.5V (via 3.3 ohm)
+ 12 = JOYCMD (via 220 ohm) 8,15,28,29 = GND
+ 13 = JOYDAT (via 22 ohm) All other pins = Not connected
+Aside from that chip, the board additionally contains some resistors,
+capacitors, z-diodes (for protection against too high voltages), a 6MHz
+oscillator (for the CPU), and a 5pin reset generator (on the cart edge
+connector, the supply pins are slightly longer than the data signal pins, so
+when inserting the cartridge, power/reset gets triggered first; the 7.5V supply
+pin is left unconnected, only 3.5V are used).
+Caution: The "diagonal edge" at the upper-left of the CXD8732AQ chip is Pin 49
+(not pin 1), following the pin numbers on the board (and the Sanyo datasheet
+pinouts), pin 1 is at the lower-left.
+
+Sanyo LC86F8604A
+8bit CPU with 132Kbyte EEPROM, 4Kbyte ROM, 256 bytes RAM, 2 timers, serial
+port, and general purpose parallel ports. The 132K EEPROM is broken into 128K
+plus 4K, the 4K might be internally used by the CPU, presumably containing the
+BIOS (not too sure if it's really containing 4K EEPROM plus 4K ROM, or if it's
+meant to be only either one).
+ 1=P40/A0 9=P13 17=TP0 25=VDD 33=A11 41=NC 49=A7 57=NC
+ 2=/RES 10=P14 18=TP1 26=NC 34=A9 42=NC 50=A6 58=NC
+ 3=TEST2 11=P15 19=TP2 27=NC 35=A8 43=NC 51=A5 59=NC
+ 4=TEST1 12=P16 20=TP3 28=NC 36=A13 44=NC 52=A4 60=NC
+ 5=P10 13=P17 21=TP4 29=VSS 37=A14 45=A17 53=NC 61=NC61
+ 6=P11 14=/CE 22=TP5 30=CF1 38=/WE 46=A16 54=NC 62=P43/A3
+ 7=P12 15=A10 23=TP6 31=CF2 39=VDD 47=A15 55=NC 63=P42/A2
+ 8=VSS 16=/OE 24=TP7 32=VDD 40=EP 48=A12 56=NC 64=P41/A1
+Ports P10..P17 have multiple functions (I/O port, data bus, serial, etc):
+ P10/DQ0/SEPMOD P12/DQ2/FSI0 P14/DQ4 P16/DQ6/SI0/FSTART
+ P11/DQ1/SCLK0/FSCLK P13/DQ3 P15/DQ5 P17/DQ7/SO0/FRW
+In March 1998, Sanyo has originally announced the LC86F8604A as an 8bit CPU
+with "2.8V FLASH, achieved for the first time in the industry", however,
+according to their datasheet, what they have finally produced is an 8bit CPU
+with "3.5V EEPROM". Although, maybe the 3.5V EEPROM version came first, and the
+2.8V FLASH was announced to be a later low-power version of the old chip;
+namely, otherwise, it'd be everyones guess what kind of memory Sony used in
+memory cards before 1998?
+
+Note
+For the actual pin-outs of the cart-edge connector, see
+--> Pinouts - Controller Ports and Memory-Card Ports
+
+Mods - Nocash PSX-XBOO Upload
+-----------------------------
+
+Nocash PSX-XBOO Connection (required)
+ GND (BOARD) --------- GND (SUBD.18-25, CNTR.19-30)
+ A16 (ROM.2) --------- SLCT (SUBD.13, CNTR.13) ;\
+ A17 (ROM.30) --------- PE (SUBD.12, CNTR.12) ; 4bit.dta.out
+ A18 (ROM.31) --------- /ACK (SUBD.10, CNTR.10) ;
+ A19 (ROM.1) --------- BUSY (SUBD.11, CNTR.11) ;/
+ /RESET ---|>|--- /INIT (SUBD.16, CNTR.31) ;-reset.in
+ D0..D7 (74HC541) --------- DATA (SUBD.2-9, CNTR.2-9) ;\
+ Y0..Y7 (74HC541) --------- D0..D7 (ROM.13-15,17-21) ; 7bit.dta.in, and
+ /OE1 (74HC541.1) --------- /EXP (CPU.98) ; 1bit.dta.clk.in
+ /OE2 (74HC541.19) --------- /OE (ROM.24) ;
+ GND (74HC541.10) --------- GND (BOARD) ;
+ VCC (74HC541.20) --------- +5V (BOARD) ;/
+
+Nocash PSX-BIOS Connection (required)
+ A0..A19 (ROM) --------- A0..A19 (EPROM)
+ D0..D7 (ROM) --------- D0..D7 (EPROM)
+ /BIOS (CPU.97)--------- /CS (EPROM.22)
+ /OE (ROM.24) --------- /OE (EPROM.24)
+ +5V (BOARD) --------- VCC (EPROM.32)
+ GND (BOARD) --------- GND (EPROM.16)
+ /CS (ROM.22) --/cut/-- /BIOS (CPU.97)
+ /CS (ROM.22) --------- +5V (BOARD) (direct, or via 100k ohm)
+
+Nocash BIOS "Modchip" Feature (optional)
+ SPU.Pin42 "data" -------|>|------ CPU.Pin149 (A20)
+ SPU.Pin5 "sync" ---------------- IC723.Pin17
+The nocash PSX bios outputs the "data" signal on the A20 address line, so
+(aside from the BIOS chip) one only needs to install a 1N4148 diode and two
+wires to unlock the CDROM. For more variants, see:
+--> CDROM Protection - Chipless Modchips
+
+Composite NTSC/PAL Mod (optional)
+--> Mods - PAL/NTSC Color Mods
+
+Component List
+ 32pin socket for EPROM
+ EPROM (or FLASH)
+ 74HC541 (8-bit 3-state noninverting buffer/line driver)
+ 1N4148 diode (for reset signal)
+ 1N4148 diode (for optional "modchip" feature)
+ 36pin Centronics socket for printer cable (or 25pin dsub)
+
+PSX-XBOO Upload BIOS
+The required BIOS is contained in no$psx (built-in in the no$psx.exe file), the
+Utility menu contains a function for creating a standalone ROM-image (file
+PSX-XBOO.ROM in no$psx folder; which can be then burned to FLASH or EPROM).
+
+Pinouts
+ ______ ______ ____ ____
+ | \/ | | \/ |
+ A19,VPP12 | 1 32 | VCC6 /OE1 |1 20| VCC
+ A16 | 2 31 | A18,/PGM D0 |2 19| /OE2
+ A15 | 3 30 | A17 D1 |3 18| Y0
+ A12 | 4 29 | A14 D2 |4 17| Y1
+ A7 | 5 28 | A13 D3 |5 74541 16| Y2
+ A6 | 6 27 | A8 D4 |6 15| Y3
+ A5 | 7 26 | A9,IDENT12 D5 |7 14| Y4
+ A4 | 8 25 | A11 D6 |8 13| Y5
+ A3 | 9 24 | /OE,VPP12 D7 |9 12| Y6
+ A2 | 10 23 | A10 GND |10 11| Y7
+ A1 | 11 22 | /CE,(/PGM) |__________|
+ A0 | 12 21 | D7
+ D0 | 13 20 | D6
+ D1 | 14 19 | D5
+ D2 | 15 18 | D4
+ GND | 16 17 | D3
+ |______________|
+
+Note
+Instead of the above internal mod, the nocash kernel clone can be also
+installed on cheat devices, which do also include DB25 connectors for parallel
+port uploads, too.
+For DB25 parallel port uploads, do the following mods to the cheat device:
+ - Datel: use the FiveWire mod to get it parallel port compatible
+ - Xplorer: simply wire DB25./INIT to EXP./RESET (with diode, if needed)
+
+Mods - PAL/NTSC Color Mods
+--------------------------
+
+The PSX hardware is more or less capable of generating both PAL and NTSC
+signals. However, it's having the bad habbit to do this automatically depending
+on the game's frame rate. And worse, it's doing it regardless of whether the
+board is having matching oscillators installed (eg. a PAL board in 60Hz mode
+will produce NTSC encoding with faulty NTSC color clock).
+ color encoding PAL NTSC
+ color clock 4.43361875MHz 3.579545MHz
+ frame rate 50Hz 60Hz
+
+RGB Cables
+RGB cables don't rely on composite PAL/NTSC color encoding, and thus don't need
+any color mods (except, see the caution on GNDed pins for missing
+53.20MHz/53.69MHz oscillators below).
+
+Newer Consoles (PU-22, PU-23, PM-41, PM-41(2))
+These consoles have 17.734MHz (PAL) or 14.318MHz (NTSC) oscillators with
+constant dividers, so the color clock will be always constant, and one does
+only need to change the color encoding:
+ /PAL (IC502.CXA2106R.pin13) ---/cut/--- /PAL (GPU.pin157)
+ /PAL (IC502.CXA2106R.pin13) ----------- GND (PAL) or VCC (NTSC)
+This forces the console to be always producing the desired composite color
+format (regardless of whether the GPU is in 50Hz or 60Hz mode).
+That works for NTSC games on PAL consoles (and vice-versa). However, it won't
+work for NTSC consoles with PAL TV Sets (for that case it'd be easiest to
+install an extra oscillator, as done on older consoles).
+
+Older Consoles (PU-7, PU-8, PU-16, PU-18, PU-20)
+These consoles have 53.20MHz (PAL) or 53.69MHz (NTSC) oscillators and the GPU
+does try to change the clock divider depending on the frame rate (thereby
+producing a nonsense clock signal that's neither PAL nor NTSC). Best workaround
+is to install an extra 4.43361875MHz (PAL) or 3.579545MHz (NTSC) oscillator
+(with internal amplifier, ie. in 4pin package, which resembles DIP14, hence the
+pin 1,7,8,14 numbering):
+ GPU ------------------/cut/--- CXA1645M.pin6 SCIN
+ GPU ------------------/cut/--- CXA1645M.pin7 /PAL
+ Osc.pin14 VCC ---------------- CXA1645M.pin12 VCC (5V)
+ Osc.pin7 GND ---------------- CXA1645M.pin1 GND
+ Osc.pin8 OUT ---------------- CXA1645M.pin6 SCIN
+ Osc.pin1 NC --
+ GND (PAL) or VCC (NTSC) ------ CXA1645M.pin7 /PAL
+Caution: Many mainboards have solder pads for both 53.20MHz and 53.69MHz
+oscillators, the missing oscillator is either GNDed or shortcut with the
+installed oscillator (varies from board to board, usually via 0 ohm resistors
+on PCB bottom side). If it's GNDed, remove that connection, and instead have it
+shortcut with the installed oscillator.
+Alternately, instead of the above mods, one could also install the missing
+oscillator (and remove its 0 ohm resistor), so the board will have both
+53.20MHz and 53.69MHz installed; that will produce perfect PAL and NTSC signals
+in 50Hz and 60Hz mode accordingly, but works only if the TV Set recognizes both
+PAL and NTSC signals.
+
+Notes
+External 4.433MHz/3.579MHz osciallors won't be synchronized with the GPU frame
+rate (normally you don't want them to be synchronized, but there's some small
+risk that they might get close to running in sync, which could result in static
+or crawling color artifacts).
+For the CXA1645 chip modded to a different console region, one should also
+change one of the resistors (see datasheet), there's no noticable difference on
+the TV picture though.
+
+Region Checks
+Some kernel versions contain regions checks (additionally to the SCEx check),
+particulary for preventing NTSC games to run on PAL consoles, or non-japanese
+games on japanese consoles. Some PAL modchips can bypass that check (by
+patching the region byte in BIOS). Expansions ROMs or nocash kernel clone could
+be also used to avoid such checks.
+
+
+No$psx Emulation Controls
+-------------------------
+
+Below are hotkeys & controls for the no$psx emulator.
+
+Emulation Hotkeys
+ ESC Stop Emulation (switch to debugger)
+ Keypad-Mul Reset
+ Keypad-Sub Same as ESC
+ Keypad-Add Whoosh (run as fast as possible)
+ Backspace Whoosh (run as fast as possible)
+
+Mouse Controller Emulation (via Mouse)
+ Left-Mouse-Button --> Pass mouse to PSX Emulation
+ Middle-Mouse-Button --> Pass mouse to Operation System
+ ESC --> Pass mouse to Operation System
+
+Lightguns (Namco GunCon, and Konami IRQ10) (via Mouse)
+ Mouse Position --> Lightgun Position
+ Left Button --> Lightgun Trigger
+ Middle Button --> Namco Button A (left), or Konami Start Button (left)
+ Right Button --> Namco Button B (right), or Konami Back Button (rear)
+XXX Konami (IRQ10) Lightguns aren't working yet (the actual lightgun is
+implemented, but the required timer0 dotclk mode isn't yet properly emulated).
+
+Dance Mat (via Keyboard)
+ Q W E or Keypad: 7 8 9 --> >< Up ()
+ A D or Keypad: 4 6 --> Lt Rt
+ Z X C or Keypad: 1 2 3 --> [] Dn /\
+Plus, Select/Start as assigned for joypads.
+
+No$psx Emulation Files
+----------------------
+
+CDROM Images
+CDROMs are supported via complete disk images (in .CCD+IMG, .CDI, .CUE+BIN,
+.MDS+MDF, or .NRG format), via single-track images (.ISO files), or as raw
+executables (.EXE files).
+Decompressing .ECM and .CDZ files is supported. Subchannel data (for
+libcrypt'ed games) can be read from .SBI, .M3S, .SUB, .MDF files. Reading from
+real CDROM drives is also supported, but does require wnaspi32.dll (which
+appears to be a problem on WinNT/Win2K and higher).
+
+Memory Card Images
+Memory Cards are stored as 128Kbyte .MCD files in MEMCARD directory. If a CDROM
+image is loaded, then the first memory card (for machine 1, slot 1A) will be
+assigned to "<cdrom_filename>.mcd". The other memory cards (for other slots or
+other machines) are just using general filenames: "_MM_N_X_.mcd"; with
+MM=Machine (01 and up), N=Slot (1 or 2), X=Multitap Sub-Slot (A..D).
+To manage files in memory cards via BIOS boot menu: Eject CDROM and reset
+emulation (to get to the boot menu), then load a CDROM image with the Autostart
+checkbox disabled in lower-left (this will load the corresponding memory card
+alongsides with the CDROM, and stays in boot menu as autostart is off).
+
+BIOS ROM Image
+No$psx contains its own PSX BIOS clone. Optionally, a copy of the original PSX
+BIOS can be stored as file PSX-BIOS.ROM in no$psx folder. Doing that may be
+useful for two purposes:
+Compatibility Issues: There are no known problems, but please let me know if
+you discover a game that works only with the original BIOS, but not with the
+nocash BIOS.
+Font Issues: The nocash BIOS doesn't contain its own SHIFT-JIS font (this font
+is used by a few games; mainly in memory card screens). By default, the nocash
+BIOS copies the font from PSX-BIOS.ROM (if it is present), otherwise it uses
+fonts from the operating system: The so-called "MS Gothic" font (if you have
+japanese fonts installed on your computer), or otherwise "Courier New" (which
+covers only latin letters of course).
+Notes: There's is also a setup option to select between nocash BIOS and
+original BIOS (the default is to use original BIOS, if present). Aside from
+using the fixed PSX-BIOS.ROM filename, you can also select .ROM files in the
+CDROM loading screen (useful if you want to test different BIOS versions).
+
+Expansion ROM Image
+Expansion ROMs can be loaded via CDROM loading screen. Supported file
+extensions are .ROM (raw rom-image) and .FCD (encrypted Xplorer rom-image). The
+files must contain valid Expansion ROM IDs at offset 004h and/or 084h,
+otherwise they are treated as normal BIOS ROMs. Typical expansion ROMs are
+Cheat Device firmwares; there is no real use loading these into no$psx, except
+for viewing them in the debugger.
+Note: Some expansions do work only with original Sony BIOS (for example, Caetla
+is using various hardcoded BIOS addresses which are incompatible with no$psx
+BIOS clone). On the contrary, Xplorer is working only with no$psx BIOS clone
+(with Sony BIOS it would place a COP0 break inside of a branch delay, which
+isn't supported by no$psx). Action Replay may refuse to start GPU transfers
+unless the GPU is NOT ready for transfer (due to misunderstanding GPU status
+bits) (this does actually 'work' on real hardware because the GPU isn't
+<instantly> ready, but that effect isn't yet emulated in no$psx, so it works
+only when manually skipping the faulty waitloop in the debugger).
+
+CDROM BIOS Image
+If present, file MC68HC05.ROM (16.5kbytes) is loaded automatically as CDROM
+BIOS image (alternately it can be loaded manually via file menu, which treats
+any 16.5Kbyte .ROM file as CDROM BIOS image). The file used ONLY if low level
+CDROM BIOS emulation is enabled in setup.
+In low level mode, timings and responses to cdrom commands are closer to real
+hardware, which might be useful for bug testing, but otherwise it isn't too
+useful or recommended (the more accurate seek times are making the cdrom
+emulation much slower; the SCEx protection is also emulated, meaning that
+region problems may occur when using a CDROM BIOS version that doesn't match
+the CDROM DISC region).
+In the debugger, use Ctrl+T toggle between MIPS and HC05 disassembler view. The
+TTY window can log various HC05 I/O events (eg. Spindle and Sled control).
+
+No$psx Emulation Notes
+----------------------
+
+Important Notes
+Do not expose the emulator to extreme heat, cold, noise, darkness, or direct
+sunlight.
+Do not drink, eat, or smoke when using this software.
+Sit upright and put your hands on the table.
+Defragment your harddisk weekly.
+Use specialized defragmentation tools.
+This product may contain rude and disturbing language.
+
+
+No$psx Debugger - Hotkeys in Debug Mode
+---------------------------------------
+
+Most debug functions are available via hotkeys and via mouse accessible popup
+boxes. The popup boxes generally also show the corresponding hotkey.
+
+ Cursor (*) Move around
+ Cursor Right Follow (in codewin: map window to jump/call dest adr)
+ Cursor Right Follow (in stckwin: map codewin to return adr)
+ Cursor Left Undo follow (if nothing to undo: goto program counter)
+ Page Up/Down (*) Move around
+ Home (*) Goto Start or to 0000
+ End (*) Goto End
+ Ret (*) Center/Uncenter current line in code window
+ Shift+Cursor Change Active Window (Code,Data,Stck,Regs)
+ Shift+Cursor (*) Toggle between Hex- and Ascii-input in data window
+ Tab (*) Toggle Standard and Symbolic Display in code window
+ Tab (*) Toggle Lower Window (Data or Break/Watch)
+ Ctrl+B Enter Breakpoint Address, Condition
+ Ctrl+N Find Next Breakpoint
+ Ctrl+G Goto Address (prompts for address) (does not affect pc)
+ Ctrl+E (*) Toggle Warnings on/off
+ Ctrl+O OS Shell (calls DOS, type 'exit' to come back)
+ Ctrl+I Inspect (Define Watchpoint address)
+ Ctrl+R Reload Cartridge
+ Ctrl+S Search (see below! this works a bit strange)
+ Ctrl+C Continue Search
+ Ctrl+V (**) Toggle Screen Size 25/50 lines (DOS version only)
+ Ctrl+D Toggle Datazone (see below)
+ Ctrl+A/T/X (*) Add/Toggle/Remove Machine (up to 12 consoles at 1 time)
+ Ctrl+T also toggles MIPS/HC05 (if low-level CD enabled)
+ Ctrl+L/W Load/Save Snapshot (RAM, CPU-state and ROM-cartname)
+ Ctrl+Left/Right (*) Decrease/Increase start address of window by one byte
+ <..> Assemble into Memory (input box appears on 1st char)
+ F1 Help
+ F2 Toggle Breakpoint at cursor
+ F3 Trace with calls executed
+ F4 Run to Cursor
+ F5 VRAM Viewer (last accessed screen, TAB toggles)
+ F6 Jump to Cursor (sets programcounter (pc) and rombank)
+ F7 Trace (Execute one instruction)
+ F8 Run until current sub-routine returns
+ F9 Run (until breakpoint or user break)
+ F10 Hardware Info Screen (splits in 50 lines DOS mode)
+ F11 Setup Screen (last accessed setup window)
+ F12 Cartridge Menu (last accessed, filename or files.lst)
+ Scroll Lock Toggle Datacur follows Codecur (or 16bit reg) on/off
+ Keypad "/" Run one Frame
+ Keypad "*" Reset and Run
+ Keypad "-" (*) Continue Run (same as F9)
+ ESC (*) Popup File Menu or close current window/menu
+ Alt+<..> (*) Popup Menus (eg. Alt+F for File Menu)
+ Alt+A Animate (Repeated trace until key pressed)
+ Alt+B Place Bookmark
+ Alt+E Edit File
+ Alt+P Profiler Window
+ Alt+X Exit No$psx
+ Right Mouse Button (*) DOS: Continue Run (same as F9), Windows: Context Menu
+ Left Mouse Button (*) Select Window, Place Cursor, Toggle Breakpoint or
+ CPU-flag, Open Popup Menu, Click Option, etc.
+
+The functions that are marked by (*) are not shown in the popup menues of the
+menu bar. Vice versa, not all functions can be accessed through hotkeys, so to
+be able to access all functions you must use both hotkeys and menu bars.
+
+No$psx Debugger - Breakpoints
+-----------------------------
+
+Normal Breaks (F2-key)
+Normal breakpoints are set (or removed) by moving the code-window cursor onto
+the desired opcode, and then pushing the F2-key.
+
+Run-to-Cursor (F4-key)
+Hitting F4-key directly starts emulation, and stops when reaching the code
+window cursor. The break address is not memorized, ie. it is used only once.
+
+Global Memory Read/Write Breaks
+This break-family allows to capture reads/writes to specific memory addresses,
+or memory areas. Membreaks are defined by pressing Ctrl+B, and then entering a
+memory address or area in square brackets,
+ [3007FFc] single address (eg. IRQ vector)
+ [6000000..6003fff] memory area (eg. first 16K of VRAM)
+followed by question and/or exclamation marks, indicating the type,
+ ? break on any read (from specified address/area)
+ !? break on any read or changed write
+ !!? break on any read or any write
+ ! break on changed write
+ !! break on any write
+Question marks ("?") capture reads. Double exclamation marks ("!!") will
+capture ALL writes, single exclamation marks ("!") capture only writes that are
+changing the memory content (ie. the new data must be different than old data).
+The ordering (eg. "!!?" or "!?!" or "?!!") is don't care.
+
+Local Conditional Breakpoints
+[XXX this isn't yet fully implemented in no$psx]
+Press Ctrl-B and define the break by entering "address, condition". The
+emulator will stop when the program counter reaches the address, and when the
+condition is true. The "$" symbol represents the current cursor address of code
+window. Examples:
+ $, r1<>0 --> break at cursor position if r1 is non-zero
+ $, r1 & 2 --> break at cursor position if bit 1 of r1 is set
+ $, r1 !& 2 --> break at cursor position if bit 1 of r1 is zero
+ 8001234, [r1]=r2 --> break at 8001234 if r1 points at a value equal to r2
+ wrchr --> break at wrchr (always, no condition, same as F2-key)
+ wrchr, r1=0d --> break at wrchr if r1 contains 0dh
+ $, [4000006] > 0A0 --> break at cursor if VCOUNT is greater than 0A0h
+ $, r4 <= r5 --> break at cursor if r4 is less or equal than r5
+ $, [r4] <> [r5] --> break at cursor if r4 points at other value than r5
+ mainloop, ..5 --> break every 5th time that pc gets to mainloop (timer)
+The conditions are verified BEFORE the instruction is executed.
+ Operators: Operands: Timer Identifier:
+ == = < > & n [nn] r ..
+ != <> <= >= !& nn [rr] rr
+Operators == and != are pseudonyms for = and <>
+
+Global Conditional Breakpoints
+[XXX this isn't yet fully implemented in no$psx]
+Global breaks are working exactly as above local breaks, except that the
+condition is verfied after <each> executed opcode. In the Ctrl+B window, enter
+a condition (without specifying a address). Examples:
+ r1 = 0 --> break whenever register r1 becomes zero
+ [4000006]>20 --> break whenever VCOUNT becomes greater than 20h
+The emulator stops only when a condition changes from false to true, ie. it
+does not permanently break after each opcode if the condition stays true for a
+while.
+
+The Break Window
+The lower left window of the debug screen is shared for Data and Breakpoints,
+use TAB-key in this window to switch between Data and Break windows. The Break
+window lists all defined breakpoints, DEL-key can be used to delete a selected
+breakpoint. When pressing ENTER on a local breakpoint, the code window will be
+moved to the break address, this works also for bookmarks (that are
+non-functional 'dummy' breaks, defined by Alt+B key in code window).
+
+No$psx Debugger - General Debug Features
+----------------------------------------
+
+Cursor Left/Right - Follow and Undo Follow
+Cursor Right in the code window moves the code window to the jump-target of the
+current opcode (if it is a jump/call opcode), or the data window to the memory
+access address (for load/store opcodes). Cursor Right in the stack window moves
+the code window to return addresses pushed on stack.
+Cursor Left in code/stack windows does undo the above (moves the windows back
+to their old addresses). Undo works also after goto (ctrl+g), and after running
+the emulation (eg. via F9-key). If there aren't any undo addresses memorized,
+then Cursor Left moves the code window to the program counter (PC).
+
+Changing MIPS register values
+In the debugger code window, typing text does prompt for MIPS assembler
+instructions to be entered. However, the assembler input box does also accept
+register assignments: For example, "r1=12345678" or "sp=8001FFFF".
+
+Dummy-Mappings
+In the debugger code/data windows, some unused addresses in the PSX memory map
+are misused to view "hidden" memory that is normally not part of the PSX memory
+map:
+ 60000000h = vram
+ 70000000h = spu-ram
+
+Filesystem Viewer (Window --> Filesystem)
+Allows to view the contents of the CDROM image (and memory cards). The whole
+filesystem is shown as tree view, which can be neatly browsed via cursur keys:
+ Up/Down Select current item
+ Left/Right Open/close folders and archives
+The viewer supports hundreds of archive formats, and dozens of compression and
+bitmap formats. The supported formats are documented here:
+--> CDROM File Formats
+
+XED Editor
+----------
+
+--> XED About
+--> XED Hotkeys
+--> XED Assembler/Debugger Interface
+--> XED Commandline based standalone version
+
+XED About
+---------
+
+About XED
+XED is a text editor, the executable is fast and small, and it includes
+comfortable editing functions. It is both intended for standard .TXT files (or
+any other ASCII files, such like .ASM for assembler source code). Also, the
+line-wrapping support (.XED files) can be used for authoring stories,
+specifications, etc. Most of the features are much the same as for other text
+editors, some special functions are pointed out below:
+
+Block Selection
+XED supports good old quality block mechanisms, allowing to copy/move the
+selection directly to cursor position by Ctrl+K,C/V hotkeys (without needing to
+use paste). For data exchange with other programs or text files, the block can
+be directly written to (or loaded from) file by Ctrl+K,R/W. And, mainstream
+copy/cut/paste functions are supported as well, by Ctrl+Ins, Shift+Del,
+Shift+Ins.
+Note: The block remains selected even when typing text, and it won't get
+deleted when touching Del-key.
+
+Condensed Display Mode
+Condensed mode is activated by "F6,C" key combination. In this mode, only lines
+beginning with colon ":", or (for assembler source code files) with
+semicolon-colon ";:", for example:
+ :Chapter IV
+ ;:---Sound Engine---
+Normal block functions can be used in this mode to Move, Copy, or Delete whole
+'chapter(s)'. Cursor keys can be used to move the cursor to a specific chapter.
+Pushing Enter or Escape terminates condensed mode.
+
+Column Block Mode
+Column mode is activated by "Ctrl+K,N" key combination. In this mode, the block
+selection appears as a rectangular area, allowing to deal with tables & columns
+in text files by using copy/delete, indent/unindent block functions.
+Typing "Ctrl+K,N" again will return to normal block mode (in which any lines
+between begin/end of the block will be selected at full length).
+
+Blank Space
+Unlike most other editors, XED allows to move the cursor to any screen
+location, including at horizontal positions after the end of the current line.
+Entering space characters at such locations advances the cursor position, but
+does not actually store space characters in the file.
+When typing text, spaces are automatically inserted between line-end and cursor
+position. Respectively, ending spaces are automatically deleted (eg. assume
+that the line contains "Hello !", deleting "!" will also remove the space
+character, internally).
+That is of course all happening behind your back, you won't have to care about
+it - but you can be sure that there'll be no hidden spaces filling up disk
+space.
+
+Tabulation Marks / TAB-Key
+The TAB Key advances the cursor to the next higher tabulation location (usually
+in steps of eight columns, counted from leftmost screen border), and the
+appropriate number of spaces is inserted into the file if necessary.
+In overwrite mode (de-/activated by INS Key), the TAB Key simply advances the
+cursor without actually inserting spaces (and without overwriting existing text
+by spaces).
+
+Tabulation Marks / CHR(9)
+When enabled in setup (default), TAB marks are automatically expanded into
+appropriate number of spaces (ie. towards next "8-column" position) when
+loading a file.
+The file is normally saved by using raw SPC characters, without any TABs.
+Optionally, it can be saved by using "best-fill" SPCs and TABs (disabled by
+default), that feature may conflict with third party tools (assemblers,
+compilers, etc). In order to reduce the risk of such problems, best-fill is
+suppressed in quoted lines (by using ' or " or <> quotation marks, eg. db
+'Hello !').
+
+Line Wrapping
+Line wrapping is enabled/disabled by "F5+W" key combination. Wrapping is
+automatically enabled when loading a file with extension ".XED".
+In the file, wrapped lines are using CR characters as soft linebreaks,
+paragraphs are terminated by normal CR,LF characters.
+Note: It'd be recommended to convert .XED files into 'standard' formats such
+like .TXT or .HTM before releasing them, but preferably NOT into disliked
+bloated file formats such like .PDF or .DOC.
+
+Word Processing
+Aside from the above line-wrapping support, no other 'word processing' features
+are included, the program provides normal 'type writer' functions, not more,
+not less. In particular, any overload such like bold or colored text, big and
+small fonts, bitmaps and different fonts are disliked.
+
+XED Hotkeys
+-----------
+
+XED recognizes both CP/M Wordstar hotkeys (also used by Borland PC compilers),
+and Norton editor hotkeys (NU.EXE). The "Ctrl+X,Y" style hotkeys are wordstar
+based, particulary including good block functions. The F4,X and Alt/Ctrl+X type
+hotkeys are norton based, particulary very useful for forwards/backwards
+searching.
+
+Standard Cursor Keys
+ Up Move line up
+ Down Move line down
+ Left Move character left
+ Right Move character right
+ Pgup Scroll page up / to top of screen
+ Pgdn Scroll page down / to bottom of screen
+ Ctrl+Home Go to start of file
+ Ctrl+End Go to end of file
+ Ctrl+Pgup Go to start of previous chapter
+ Ctrl+Pgdn Go to start if next chapter
+ Home Go to start of line
+ End Go to end of line
+ Ctrl+Left Move word left
+ Ctrl+Right Move word right
+ Ins Toggle Insert/Overwrite mode
+ Del Delete char below cursor
+ Backspace Delete char left of cursor
+ Tab Move to next tabulation mark
+ Enter New line/paragraph end
+ Esc Quit (or Alt+X, F3+Q, Ctrl+K+D, Ctrl+K+Q, Ctrl+K+X)
+Note: Pgup/Pgdn are moving the cursor to top/bottom of screen, page scrolling
+takes place only if the cursor was already at that location.
+
+Editor Keys
+ Ctrl+Y Delete line (or Alt+K)
+ Alt+L Delete to line end (or Ctrl+Q,Y)
+ Alt+V Caseflip to line end
+ Ctrl+V Caseflip from line beginning
+
+Norton Search/Replace Functions
+ Alt+F Norton - search/replace, forwards
+ Ctrl+F Norton - search/replace, backwards
+ Alt+C Norton - continue search/replace, forwards (or Ctrl+Down)
+ Ctrl+C Norton - continue search/replace, backwards (or Ctrl+Up)
+Search: Type "Alt/Ctrl+F, String, Enter".
+Search+replace: "Type Alt/Ctrl+F, String1, Alt+F, String2, Enter".
+Non-case sensitive: Terminate by Escape instead of Enter.
+
+Wordstar Search/Replace Functions
+ Ctrl+Q,F Wordstar - search
+ Ctrl+Q,A Wordstar - replace
+ Ctrl+L Wordstar - continue search/replace
+Search options: B=Backwards, G=Global, N=No query,
+U=non-casesensitive, W=whole words only, n=n times.
+
+Disk Commands
+ F3,E Save+exit
+ F3,S Save (or Ctrl+K,S)
+ F3,N Edit new file
+ F3,A Append a file
+See also: Block commands (read/write block).
+
+Block Selection
+ Shift+Cursor Select block begin..end
+ Ctrl+K,B Set block begin (or F4,S)
+ Ctrl+K,K Set block end (or F4,S)
+ Ctrl+K,H Remove/hide block markers (or F4,R)
+ F4,L Mark line including ending CRLF (or Ctrl+K,L)
+ F4,E Mark line excluding ending CRLF
+ Ctrl+K,T Mark word
+ Ctrl+K,N Toggle normal/column blocktype
+
+Clipboard Commands
+ Shift+Ins Paste from Clipboard
+ Shift+Del Cut to Clipboard
+ Ctrl+Ins Copy to Clipboard
+ Ctrl+Del Delete Block
+
+Block Commands
+ Ctrl+K,C Copy block (or F4,C)
+ Ctrl+K,V Move block (or F4,M)
+ Ctrl+K,Y Delete block (or F4,D)
+ Ctrl+K,P Print block (or F7,B)
+ Ctrl+Q,B Find block begin (or F4,F)
+ Ctrl+Q,K Find block end (or F4,F)
+ Ctrl+K,R Read block from disk towards cursor location
+ Ctrl+K,W Write block to disk
+ Ctrl+K,U Unindent block (delete one space at begin of each line)
+ Ctrl+K,I Indent block (insert one space at begin of each line)
+ F5,F Format block (with actual x-wrap size) (or ;Ctrl+B)
+ F8,A Add values within column-block
+
+Setup Commands
+ F11 Setup menu (or F8,S)
+ F5,S Save editor configuration
+ F5,L Set line len for word wrap (or Ctrl+O,R)
+ F5,W Wordwrap on/off (or Ctrl+O,W) (*)
+ F5,I Auto indent on/off (or Ctrl+O,I)
+ F5,T Set tab display spacing
+(*) Wrapped lines will be terminated by CR, paragraphs by CRLF.
+
+Other
+ F1 Help
+ F2 Status (displays info about file & currently selected block)
+ F8,M Make best fill tabs
+ F8,T Translate all tabs to spaces
+ SrcLock Freeze cursor when typing text ("useful" for backwards writing)
+ Ctrl+O,C Center current line
+ Ctrl+K,# Set marker (#=0..9)
+ Ctrl+Q,# Move to marker (#=0..9)
+ Ctrl+Q,P Move to previous pos
+ F6,C Condensed display mode on/off (*)
+ Ctrl+G Go to line nnnn (or F6,G) (or commandline switch /l:nnnn)
+(*) only lines starting with ':' or ';:' will be displayed. cursor and block
+commands can be used (e.g. to copy a text-sequence by just marking it's
+headline)
+
+Hex-Edit Keys (Binary Files)
+This mode is activated by /b commandline switch, allowing to view and modify
+binary files. Aside from normal cursor keys, the following hotkeys are used:
+ Tab Toggle between HEX and ASC mode (or Shift+Left/Right)
+ Ctrl+Arrow Step left/right one full byte (instead one single HEX digit)
+ Ctrl+G Goto hex-address
+ Ctrl+K,S Save file (as usually)
+
+Printer Commands
+ F7,P Print file
+ F7,B Print block (or Ctrl+K,P)
+ F7,E Eject page
+ F7,S Set page size
+More printer options can be found in setup. Printing was working well (at least
+with my own printer) in older XED versions, but it is probably badly bugged (at
+least untested) for years now.
+
+XED Assembler/Debugger Interface
+--------------------------------
+
+Nocash Debuggers
+The XED editor provides simple but very useful interaction with the various
+nocash debuggers/emulators (no$gba, no$gmb, no$cpc, no$msx, no$c64, no$2k6,
+no$zx, no$nes, no$sns, no$x51).
+The editor can be launched from inside of the debugger (by Alt+E hotkey, by
+retaining the recently edited line number when re-launching the editor).
+And, when editing assembler source code files, F9-key can used to launch the
+assembler from inside of XED. That is, the file is saved to disk, the A22i
+assembler is started (built-in in all debuggers), and, in case of successful
+assembly, the program is loaded & started in the emulator. Otherwise, the
+assembler displays a list of errors, and the editor is moved directly to the
+source code line number in which the first error has occured.
+
+16bit DOS debuggers
+The XED editor is included built-in in all nocash windows debuggers, and in the
+no$gba 32bit DOS version only.
+For use with other nocash 16bit DOS debuggers the XED editor must be downloaded
+separately at http://problemkaputt.de/xed.htm, and must be installed in a
+directory which is included in your PATH statement.
+
+XED Commandline based standalone version
+----------------------------------------
+
+Standalone 16bit DOS version
+This version is written in turbo pascal, nevertheless fast enough to work on
+computer with less than 10MHz. It uses 16bit 8086 code, and works with all
+80x86 compatible CPUs, including very old XTs.
+The downside is that it is restricted to Conventional DOS Memory, so that the
+maximum filesize is 640K (actually less, because the program and operating
+system need to use some of that memory).
+
+Using the 32bit debugger-built-in version as 32bit standalone editor
+I haven't yet compiled a 32bit standalone version, however, any of the no$xxx
+32bit debuggers can be used for that purpose. By commandline input:
+ no$xxx /x <filename> Edit text file in standalone mode
+ no$xxx /b <filename> Edit binary file in standalone hexedit mode
+
+Standalone Commandline Syntax
+Syntax: XED <filename> [/l:<line number>] | /?
+ <name> Filename, optionally d:\path\name.ext
+ /? Displays commandline help
+ /l:<nnn> Moves to line number nnn after loading
+The filename does not require to include an extension, the program
+automatically loads the first existing file with any of following extensions
+appended: XED, ASM, ASC, INC, BAT, TXT, HTM, DOC, A22, PAS.
+
+Standalone DOS Return Value
+XED returns a three-byte return value after closing the program. This data is
+used when calling XED as external editor from inside of nocash DOS debuggers,
+but it might be also useful for other purposes.
+Because normal DOS return values are limited to 8bits only, the three bytes are
+written into video RAM at rightmost three character locations in first line:
+ VSEG:77*2 Exit code (00h=Exit normal, F9h=Exit by F9-key)
+ VSEG:78*2 Line number (Lower 8bits, 1..65536 in total)
+ VSEG:79*2 Line number (Upper 8bits)
+The color attribute for these characters is set to zero (invisible, black on
+black). Use INT 10h/AH=0Fh to determine the current video mode (AL AND 7Fh), if
+it is monochrome (07h) then use VSEG=B000h, otherwise VSEG=B800h.
+
+
+
+About & Credits
+---------------
+
+Credits
+GPU.TXT by doomed/padua; based on info from K-communications & Nagra/Blackbag
+GTE.TXT by doomed@c64.org / psx.rules.org
+SPU.TXT by doomed@c64.org / psx.rules.org
+CDINFO.TXT by doomed with big thanks to Barubary, who rewrote a large part
+SYSTEM.TXT by doomed with thanx to Herozero for breakpoint info
+PS_ENG.TXT PlayStation PAD/Memory Interface Protocol by HFB03536
+IDT79R3041 Hardware User's Manual by Integrated Device Technology, Inc.
+IDTR3051, R3052 RISController User's Manual by Integrated Device Technology
+PSX.* by Joshua Walker (additional details in various distorted file formats)
+LIBMIRAGE by Rok; info/source code for various cdrom-image formats
+psxdev.ru; cdrom sub-cpu decapping
+
+PSXSPX homepage
+http://problemkaputt.de/psx.htm no$psx emulator/debugger
+http://problemkaputt.de/psx-spx.htm psx specs in html formal
+http://problemkaputt.de/psx-spx.txt psx specs in text formal
+
+Contact
+http://problemkaputt.de/email.htm (spam-shielded)
+
+
+Index
+-----
+
+--> Contents
+--> Memory Map
+--> I/O Map
+--> Graphics Processing Unit (GPU)
+--> GPU I/O Ports, DMA Channels, Commands, VRAM
+--> GPU Render Polygon Commands
+--> GPU Render Line Commands
+--> GPU Render Rectangle Commands
+--> GPU Rendering Attributes
+--> GPU Memory Transfer Commands
+--> GPU Other Commands
+--> GPU Display Control Commands (GP1)
+--> GPU Status Register
+--> GPU Versions
+--> GPU Depth Ordering
+--> GPU Video Memory (VRAM)
+--> GPU Texture Caching
+--> GPU Timings
+--> GPU (MISC)
+--> Geometry Transformation Engine (GTE)
+--> GTE Overview
+--> GTE Registers
+--> GTE Saturation
+--> GTE Opcode Summary
+--> GTE Coordinate Calculation Commands
+--> GTE General Purpose Calculation Commands
+--> GTE Color Calculation Commands
+--> GTE Division Inaccuracy
+--> Macroblock Decoder (MDEC)
+--> MDEC I/O Ports
+--> MDEC Commands
+--> MDEC Decompression
+--> MDEC Data Format
+--> Sound Processing Unit (SPU)
+--> SPU Overview
+--> SPU ADPCM Samples
+--> SPU ADPCM Pitch
+--> SPU Volume and ADSR Generator
+--> SPU Voice Flags
+--> SPU Noise Generator
+--> SPU Control and Status Register
+--> SPU Memory Access
+--> SPU Interrupt
+--> SPU Reverb Registers
+--> SPU Reverb Formula
+--> SPU Reverb Examples
+--> SPU Unknown Registers
+--> Interrupts
+--> DMA Channels
+--> Timers
+--> CDROM Drive
+--> CDROM Controller I/O Ports
+--> CDROM Controller Command Summary
+--> CDROM - Control Commands
+--> CDROM - Seek Commands
+--> CDROM - Read Commands
+--> CDROM - Status Commands
+--> CDROM - CD Audio Commands
+--> CDROM - Test Commands
+--> CDROM - Test Commands - Version, Switches, Region, Chipset, SCEx
+--> CDROM - Test Commands - Test Drive Mechanics
+--> CDROM - Test Commands - Prototype Debug Transmission
+--> CDROM - Test Commands - Read/Write Decoder RAM and I/O Ports
+--> CDROM - Test Commands - Read HC05 SUB-CPU RAM and I/O Ports
+--> CDROM - Secret Unlock Commands
+--> CDROM - Video CD Commands
+--> CDROM - Mainloop/Responses
+--> CDROM - Response Timings
+--> CDROM - Response/Data Queueing
+--> CDROM Disk Format
+--> CDROM Subchannels
+--> CDROM Sector Encoding
+--> CDROM Scrambling
+--> CDROM XA Subheader, File, Channel, Interleave
+--> CDROM XA Audio ADPCM Compression
+--> CDROM ISO Volume Descriptors
+--> CDROM ISO File and Directory Descriptors
+--> CDROM ISO Misc
+--> CDROM Extension Joliet
+--> CDROM File Formats
+--> CDROM File Official Sony File Formats
+--> CDROM File Playstation EXE and SYSTEM.CNF
+--> CDROM File PsyQ .CPE Files (Debug Executables)
+--> CDROM File PsyQ .SYM Files (Debug Information)
+--> CDROM File Video Texture Image TIM/PXL/CLT (Sony)
+--> CDROM File Video Texture/Bitmap (Other)
+--> CDROM File Video Texture/Bitmap (TGA)
+--> CDROM File Video Texture/Bitmap (PCX)
+--> CDROM File Video 2D Graphics CEL/BGD/TSQ/ANM/SDF (Sony)
+--> CDROM File Video 3D Graphics TMD/PMD/TOD/HMD/RSD (Sony)
+--> CDROM File Video STR Streaming and BS Picture Compression (Sony)
+--> CDROM File Video Streaming STR (Sony)
+--> CDROM File Video Streaming STR Variants
+--> CDROM File Video Streaming Framerate
+--> CDROM File Video Streaming Audio
+--> CDROM File Video Streaming Chunk-based formats
+--> CDROM File Video Streaming Mis-mastered files
+--> CDROM File Video BS Compression Versions
+--> CDROM File Video BS Compression Headers
+--> CDROM File Video BS Compression DC Values
+--> CDROM File Video BS Compression AC Values
+--> CDROM File Video BS Picture Files
+--> CDROM File Video Wacwac MDEC Streams
+--> CDROM File Video Polygon Streaming
+--> CDROM File Audio Single Samples VAG (Sony)
+--> CDROM File Audio Sample Sets VAB and VH/VB (Sony)
+--> CDROM File Audio Sequences SEQ/SEP (Sony)
+--> CDROM File Audio Streaming XA-ADPCM
+--> CDROM File Audio CD-DA Tracks
+--> CDROM File Archives with Filename
+--> CDROM File Archives with Offset and Size
+--> CDROM File Archives with Offset
+--> CDROM File Archives with Size
+--> CDROM File Archives with Chunks
+--> CDROM File Archives with Folders
+--> CDROM File Archive HUG/IDX/BIZ (Power Spike)
+--> CDROM File Archive TOC/DAT/LAY
+--> CDROM File Archive WAD (Doom)
+--> CDROM File Archive WAD (Cardinal Syn/Fear Effect)
+--> CDROM File Archive DIR/DAT (One/Viewpoint)
+--> CDROM File Archive Darkworks Chunks (Alone in the Dark)
+--> CDROM File Archive Blue Chunks (Blue's Clues)
+--> CDROM File Archive HED/CDF (Parasite Eve 2)
+--> CDROM File Archive IND/WAD (MTV Music Generator)
+--> CDROM File Archive GAME.RSC (Colonly Wars Red Sun)
+--> CDROM File Archive BIGFILE.DAT (Soul Reaver)
+--> CDROM File Archive FF8 IMG (Final Fantasy VIII)
+--> CDROM File Archive FF9 IMG (Final Fantasy IX)
+--> CDROM File Archive GTFS (Gran Turismo 2)
+--> CDROM File Archive Nightmare Project: Yakata
+--> CDROM File Archive FAdj0500 (Klonoa)
+--> CDROM File Archives in Hidden Sectors
+--> CDROM File Archive HED/DAT/BNS/STR (Ape Escape)
+--> CDROM File Archive WAD.WAD, BIG.BIN, JESTERS.PKG (Crash/Herc/Pandemonium)
+--> CDROM File Archive BIGFILE.BIG (Gex)
+--> CDROM File Archive BIGFILE.DAT (Gex - Enter the Gecko)
+--> CDROM File Archive FF9 DB (Final Fantasy IX)
+--> CDROM File Archive Ace Combat 2 and 3
+--> CDROM File Archive NSD/NSF (Crash Bandicoot 1-3)
+--> CDROM File Archive STAGE.DIR and *.DAT (Metal Gear Solid)
+--> CDROM File Archive DRACULA.DAT (Dracula)
+--> CDROM File Archive Croc 1 (DIR, WAD, etc.)
+--> CDROM File Archive Croc 2 (DIR, WAD, etc.)
+--> CDROM File Archive Headerless Archives
+--> CDROM File Compression
+--> CDROM File Compression LZSS (Moto Racer 1 and 2)
+--> CDROM File Compression LZSS (Dino Crisis 1 and 2)
+--> CDROM File Compression LZSS (Serial Experiments Lain)
+--> CDROM File Compression ZOO/LZSS
+--> CDROM File Compression Ulz/ULZ (Namco)
+--> CDROM File Compression SLZ/01Z (chunk-based compressed archive)
+--> CDROM File Compression LZ5 and LZ5-variants
+--> CDROM File Compression PCK (Destruction Derby Raw)
+--> CDROM File Compression GT-ZIP (Gran Turismo 1 and 2)
+--> CDROM File Compression GT20 and PreGT20
+--> CDROM File Compression HornedLZ
+--> CDROM File Compression LZS (Gundam Battle Assault 2)
+--> CDROM File Compression BZZ
+--> CDROM File Compression RESOURCE (Star Wars Rebel Assault 2)
+--> CDROM File Compression TIM-RLE4/RLE8
+--> CDROM File Compression RLE_16
+--> CDROM File Compression PIM/PRS (Legend of Mana)
+--> CDROM File Compression BPE (Byte Pair Encoding)
+--> CDROM File Compression RNC (Rob Northen Compression)
+--> CDROM File Compression Darkworks
+--> CDROM File Compression Blues
+--> CDROM File Compression Z (Running Wild)
+--> CDROM File Compression ZAL (Z-Axis)
+--> CDROM File Compression EA Methods
+--> CDROM File Compression EA Methods (LZSS RefPack)
+--> CDROM File Compression EA Methods (Huffman)
+--> CDROM File Compression EA Methods (BPE)
+--> CDROM File Compression EA Methods (RLE)
+--> CDROM File Compression ZIP/GZIP/ZLIB (Inflate/Deflate)
+--> Inflate - Core Functions
+--> Inflate - Initialization & Tree Creation
+--> Inflate - Headers and Checksums
+--> CDROM File Compression LArc/LHarc/LHA (LZS/LZH)
+--> CDROM File Compression ARJ
+--> CDROM File Compression ARC
+--> CDROM File Compression RAR
+--> CDROM File Compression ZOO
+--> CDROM File Compression nCompress.Z
+--> CDROM File Compression Octal Oddities (TAR, CPIO, RPM)
+--> CDROM File Compression MacBinary, BinHex, PackIt, StuffIt, Compact Pro
+--> CDROM File XYZ and Dummy/Null Files
+--> CDROM Protection - SCEx Strings
+--> CDROM Protection - Bypassing it
+--> CDROM Protection - Modchips
+--> CDROM Protection - Chipless Modchips
+--> CDROM Protection - LibCrypt
+--> CDROM Disk Images CCD/IMG/SUB (CloneCD)
+--> CDROM Disk Images CDI (DiscJuggler)
+--> CDROM Disk Images CUE/BIN/CDT (Cdrwin)
+--> CDROM Disk Images MDS/MDF (Alcohol 120%)
+--> CDROM Disk Images NRG (Nero)
+--> CDROM Disk Image/Containers CDZ
+--> CDROM Disk Image/Containers ECM
+--> CDROM Subchannel Images
+--> CDROM Disk Images Other Formats
+--> CDROM Internal Info on PSX CDROM Controller
+--> CDROM Internal HC05 Instruction Set
+--> CDROM Internal HC05 On-Chip I/O Ports
+--> CDROM Internal HC05 On-Chip I/O Ports - Extras
+--> CDROM Internal HC05 I/O Port Usage in PSX
+--> CDROM Internal HC05 Motorola Selftest Mode
+--> CDROM Internal HC05 Motorola Selftest Mode (52pin chips)
+--> CDROM Internal HC05 Motorola Selftest Mode (80pin chips)
+--> CDROM Internal CXD1815Q Sub-CPU Configuration Registers
+--> CDROM Internal CXD1815Q Sub-CPU Sector Status Registers
+--> CDROM Internal CXD1815Q Sub-CPU Address Registers
+--> CDROM Internal CXD1815Q Sub-CPU Misc Registers
+--> CDROM Internal Commands CX(0x..3x) - CXA1782BR Servo Amplifier
+--> CDROM Internal Commands CX(4x..Ex) - CXD2510Q Signal Processor
+--> CDROM Internal Commands CX(0x..Ex) - CXD2545Q Servo/Signal Combo
+--> CDROM Internal Commands CX(0x..Ex) - CXD2938Q Servo/Signal/SPU Combo
+--> CDROM Internal Commands CX(xx) - Notes
+--> CDROM Internal Commands CX(xx) - Summary of Used CX(xx) Commands
+--> CDROM Internal Coefficients (for CXD2545Q)
+--> CDROM Video CDs (VCD)
+--> VCD ISO Basic Files (INFO, ENTRIES, AVSEQnn, ISO Filesystem)
+--> VCD ISO Playback Control PBC Files (PSD, LOT, ITEMnnnn)
+--> VCD ISO Search Files (SCANDATA, SEARCH, TRACKS, SPICONTX)
+--> VCD ISO Misc files (CAPTnn, AUDIOnn, KARINFO, PICTURES, CDI)
+--> VCD MPEG-1 Multiplex Stream
+--> VCD MPEG-1 Video Stream
+--> VCD MP2 Audio Stream
+--> Controllers and Memory Cards
+--> Controller and Memory Card I/O Ports
+--> Controller and Memory Card Misc
+--> Controller and Memory Card Signals
+--> Controller and Memory Card Multitap Adaptor
+--> Controllers - Communication Sequence
+--> Controllers - Standard Digital/Analog Controllers
+--> Controllers - Mouse
+--> Controllers - Racing Controllers
+--> Controllers - Lightguns
+--> Controllers - Lightguns - Namco (GunCon)
+--> Controllers - Lightguns - Konami Justifier/Hyperblaster (IRQ10)
+--> Controllers - Lightguns - PSX Lightgun Games
+--> Controllers - Configuration Commands
+--> Controllers - Vibration/Rumble Control
+--> Controllers - Analog Buttons (Dualshock2)
+--> Controllers - Dance Mats
+--> Controllers - Fishing Controllers
+--> Controllers - I-Mode Adaptor (Mobile Internet)
+--> Controllers - Keyboards
+--> Controllers - Additional Inputs
+--> Controllers - Misc
+--> Memory Card Read/Write Commands
+--> Memory Card Data Format
+--> Memory Card Images
+--> Memory Card Notes
+--> Pocketstation
+--> Pocketstation Overview
+--> Pocketstation I/O Map
+--> Pocketstation Memory Map
+--> Pocketstation IO Video and Audio
+--> Pocketstation IO Interrupts and Buttons
+--> Pocketstation IO Timers and Real-Time Clock
+--> Pocketstation IO Infrared
+--> Pocketstation IO Memory-Control
+--> Pocketstation IO Communication Ports
+--> Pocketstation IO Power Control
+--> Pocketstation SWI Function Summary
+--> Pocketstation SWI Misc Functions
+--> Pocketstation SWI Communication Functions
+--> Pocketstation SWI Execute Functions
+--> Pocketstation SWI Date/Time/Alarm Functions
+--> Pocketstation SWI Flash Functions
+--> Pocketstation SWI Useless Functions
+--> Pocketstation BU Command Summary
+--> Pocketstation BU Standard Memory Card Commands
+--> Pocketstation BU Basic Pocketstation Commands
+--> Pocketstation BU Custom Pocketstation Commands
+--> Pocketstation File Header/Icons
+--> Pocketstation File Images
+--> Pocketstation XBOO Cable
+--> Serial Port (SIO)
+--> Expansion Port (PIO)
+--> EXP1 Expansion ROM Header
+--> EXP2 Dual Serial Port (for TTY Debug Terminal)
+--> EXP2 DTL-H2000 I/O Ports
+--> EXP2 Post Registers
+--> EXP2 Nocash Emulation Expansion
+--> Memory Control
+--> Unpredictable Things
+--> CPU Specifications
+--> CPU Registers
+--> CPU Opcode Encoding
+--> CPU Load/Store Opcodes
+--> CPU ALU Opcodes
+--> CPU Jump Opcodes
+--> CPU Coprocessor Opcodes
+--> CPU Pseudo Opcodes
+--> COP0 - Register Summary
+--> COP0 - Exception Handling
+--> COP0 - Misc
+--> COP0 - Debug Registers
+--> Kernel (BIOS)
+--> BIOS Overview
+--> BIOS Memory Map
+--> BIOS Function Summary
+--> BIOS File Functions
+--> BIOS File Execute and Flush Cache
+--> BIOS CDROM Functions
+--> BIOS Memory Card Functions
+--> BIOS Interrupt/Exception Handling
+--> BIOS Event Functions
+--> BIOS Event Summary
+--> BIOS Thread Functions
+--> BIOS Timer Functions
+--> BIOS Joypad Functions
+--> BIOS GPU Functions
+--> BIOS Memory Allocation
+--> BIOS Memory Fill/Copy/Compare (SLOW)
+--> BIOS String Functions
+--> BIOS Number/String/Character Conversion
+--> BIOS Misc Functions
+--> BIOS Internal Boot Functions
+--> BIOS More Internal Functions
+--> BIOS PC File Server
+--> BIOS TTY Console (std_io)
+--> BIOS Character Sets
+--> BIOS Control Blocks
+--> BIOS Boot State
+--> BIOS Versions
+--> BIOS Patches
+--> Arcade Cabinets
+--> Cheat Devices
+--> Cheat Devices - Datel I/O
+--> Cheat Devices - Datel DB25 Comms Link Protocol
+--> Cheat Devices - Datel Chipset Pinouts
+--> Cheat Devices - Datel Cheat Code Format
+--> Cheat Devices - Xplorer Memory and I/O Map
+--> Cheat Devices - Xplorer DB25 Parallel Port Function Summary
+--> Cheat Devices - Xplorer DB25 Parallel Port Command Handler
+--> Cheat Devices - Xplorer DB25 Parallel Port Low Level Transfer Protocol
+--> Cheat Devices - Xplorer Versions
+--> Cheat Devices - Xplorer Chipset Pinouts
+--> Cheat Devices - Xplorer Cheat Code Format
+--> Cheat Devices - Xplorer Cheat Code and ROM-Image Decryption
+--> Cheat Devices - FLASH/EEPROMs
+--> PSX Dev-Board Chipsets
+--> Hardware Numbers
+--> Pinouts
+--> Pinouts - Controller Ports and Memory-Card Ports
+--> Pinouts - Audio, Video, Power, Expansion Ports
+--> Pinouts - SIO Pinouts
+--> Pinouts - Chipset Summary
+--> Pinouts - CPU Pinouts
+--> Pinouts - GPU Pinouts (for old 160-pin GPU)
+--> Pinouts - GPU Pinouts (for new 208-pin GPU)
+--> Pinouts - SPU Pinouts
+--> Pinouts - DRV Pinouts
+--> Pinouts - VCD Pinouts
+--> Pinouts - HC05 Pinouts
+--> Pinouts - MEM Pinouts
+--> Pinouts - CLK Pinouts
+--> Pinouts - PWR Pinouts
+--> Pinouts - Component List and Chipset Pin-Outs for Digital Joypad, SCPH-1080
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1150
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-1200
+--> Pinouts - Component List and Chipset Pin-Outs for Analog Joypad, SCPH-110
+--> Pinouts - Component List and Chipset Pin-Outs for Dualshock2, SCPH-10010
+--> Pinouts - Component List and Chipset Pin-Outs for Namco Lightgun, NPC-103
+--> Pinouts - Component List and Chipset Pin-Outs for Multitap, SCPH-1070
+--> Pinouts - Memory Cards
+--> Mods - Nocash PSX-XBOO Upload
+--> Mods - PAL/NTSC Color Mods
+--> No$psx Emulation Controls
+--> No$psx Emulation Files
+--> No$psx Emulation Notes
+--> No$psx Debugger - Hotkeys in Debug Mode
+--> No$psx Debugger - Breakpoints
+--> No$psx Debugger - General Debug Features
+--> XED Editor
+--> XED About
+--> XED Hotkeys
+--> XED Assembler/Debugger Interface
+--> XED Commandline based standalone version
+--> About & Credits
diff --git a/roms/scph1001.bin b/roms/scph1001.bin
Binary files differ.
diff --git a/src/bios.c b/src/bios.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "../include/bios.h"
+#include "../include/types.h"
+
+BIOS*
+BIOS_new(const char* path)
+{
+ BIOS *b;
+ long pos;
+ FILE* f;
+
+ f = fopen(path, "rb");
+ if (f == NULL)
+ {
+ perror("ERROR");
+ exit(EXIT_FAILURE);
+ }
+
+ fseek(f, 0, SEEK_END);
+
+ pos = ftell(f);
+ /* If not 512KB then exit */
+ if (pos != 512*1024)
+ {
+ fprintf(stderr, "INVALID BIOS_SIZE\n"); exit(1);
+ }
+
+ fseek(f, 0, SEEK_SET);
+
+ b = (BIOS*)malloc(sizeof(BIOS));
+ b->data = (unsigned char*)malloc(sizeof(unsigned char)*pos);
+ fread(b->data, 1, pos, f);
+
+ fclose(f);
+
+ return b;
+}
+
+u32
+BIOS_load32(BIOS* b, u32 offset)
+{
+ return (b->data[offset + 3] << 24) |
+ (b->data[offset + 2] << 16) |
+ (b->data[offset + 1] << 8) |
+ (b->data[offset + 0]);
+}
diff --git a/src/cpu.c b/src/cpu.c
@@ -0,0 +1,197 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../include/interconnect.h"
+#include "../include/cpu.h"
+#include "../include/types.h"
+#include "../include/defs.h"
+
+CPU*
+new_cpu(Interconnect* inter) {
+ CPU* cpu = (CPU*)malloc(sizeof(CPU));
+ cpu->pc = 0xBFC00000;
+ cpu->sr = 0x0;
+ cpu->inter = inter;
+ cpu->load._0 = 0; cpu->load._1 = 0;
+ cpu->next_instruction = new_instr(0x0); /* NOP */
+ memset(cpu->regs, 0, sizeof(cpu->regs));
+ //memset(cpu->out_regs, 0, sizeof(cpu->out_regs));
+ return cpu;
+}
+
+u32 CPU_load32(CPU* cpu, u32 addr) { return INTER_load32(cpu->inter, addr); }
+//u16 CPU_load16(CPU* cpu, u16 addr) { return INTER_load16(cpu->INTER, addr); }
+//u8 CPU_load8(CPU* cpu, u8 addr) { return INTER_load8(cpu->INTER, addr); }
+//
+void CPU_store32(CPU* cpu, u32 addr, u32 val) { INTER_store32(cpu->inter, addr, val); }
+//u16 CPU_store16(CPU* cpu, u16 addr) { return INTER_store16(cpu->INTER, addr); }
+//u8 CPU_store8(CPU* cpu, u8 addr) { return INTER_store8(cpu->INTER, addr); }
+
+void
+set_reg(CPU* cpu, u32 reg, u32 val)
+{
+ cpu->regs[reg] = val;
+ cpu->regs[0] = 0;
+}
+
+u32
+reg(CPU* cpu, u32 reg)
+{
+ return cpu->regs[reg];
+}
+
+void
+op_lui(CPU* cpu, instruction* i)
+{
+ u32 v = i->imm << 16;
+ set_reg(cpu, i->t, v);
+}
+
+void
+op_or(CPU* cpu, instruction* i)
+{
+ u32 v;
+ v = reg(cpu, i->s) | reg(cpu, i->t);
+ set_reg(cpu, i->d, v);
+ //printf("d: %d = %d\n", i->d, v);
+}
+
+void
+op_ori(CPU* cpu, instruction* i)
+{
+ u32 v;
+ v = reg(cpu, i->s) | i->imm;
+ set_reg(cpu, i->t, v);
+}
+
+void
+op_sw(CPU* cpu, instruction* i)
+{
+ u32 imm_se, t, s, addr, v;
+
+ imm_se = i->imm_se;
+ t = i->t;
+ s = i->s;
+
+ addr = reg(cpu, s) + imm_se;
+ v = reg(cpu, t);
+ CPU_store32(cpu, addr, v);
+}
+
+void
+op_sll(CPU* cpu, instruction* i)
+{
+ u32 shift, t, d, v;
+
+ shift = i->shift;
+ t = i->t;
+ d = i->d;
+
+ v = reg(cpu, t) << shift;
+ set_reg(cpu, d, v);
+
+}
+
+void
+op_addiu(CPU* cpu, instruction* i)
+{
+ u32 v;
+ v = reg(cpu, i->s) + i->imm_se;
+ set_reg(cpu, i->t, v);
+}
+
+void
+op_j(CPU* cpu, instruction* i)
+{
+ cpu->pc = (cpu->pc & 0xf0000000) | (i->imm_jump << 2);
+}
+
+void
+op_mtc0(CPU* cpu, instruction* i)
+{
+ return;
+}
+
+
+void
+op_cop0(CPU* cpu, instruction* i)
+{
+ switch (i->cop_opcode) {
+ case 0x04: op_mtc0(cpu, i); break;
+ default: PANIC("Unhandled cop0 instruction %08X", i->_0);
+ }
+}
+
+void
+CPU_decode_and_execute(CPU* cpu, instruction* i)
+{
+
+ switch(i->fn) {
+ case 0x0:
+ {
+ switch(i->sub) {
+ case 0x0: op_sll(cpu, i); break;
+ case 0x25: op_or(cpu, i); break;
+ default: PANIC("Unhandled instruction %08X\n", i->_0); break;
+ }
+ break;
+ }
+ case 0x0f: op_lui(cpu, i); break;
+ case 0x0d: op_ori(cpu, i); break;
+ case 0x2b: op_sw(cpu, i); break;
+ case 0x09: op_addiu(cpu, i); break;
+ case 0x02: op_j(cpu, i); break;
+ case 0x10: op_cop0(cpu, i); break;
+ default: PANIC("Unhandled instruction %08X\n", i->_0);break;
+ }
+
+}
+
+void
+CPU_run_next_instruction(CPU* cpu)
+{
+ u32 pc = cpu->pc;
+
+ /* Use previously loaded instruction */
+ instruction i = cpu->next_instruction;
+
+ cpu->next_instruction = new_instr(CPU_load32(cpu, pc));
+
+ cpu->pc += 4;
+
+ CPU_decode_and_execute(cpu, &i);
+
+ //memcpy(cpu->regs, cpu->out_regs, sizeof(u32) * 32);
+}
+
+instruction
+new_instr(u32 i)
+{
+ instruction ins;
+ ins._0 = i;
+ ins.fn = i >> 26;
+ ins.sub = i & 0x3f;
+ ins.s = (i >> 21) & 0x1f;
+ ins.t = (i >> 16) & 0x1f;
+ ins.d = (i >> 11) & 0x1f;
+ ins.shift = (i >> 6) & 0x1f;
+ ins.imm = i & 0xffff;
+ ins.imm_se = (u32)((i16)(i & 0xffff));
+ ins.imm_jump = i & 0x3ffffff;
+ ins.cop_opcode = (i >> 21) & 0x1f;
+ //print_instr(&ins);
+ return ins;
+}
+
+//void
+//print_instr(instruction *ins)
+//{
+// fprintf(stdout, "\n");
+// fprintf(stdout,"FUNCTION: "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(ins->fn));
+// fprintf(stdout,"SUBFUNCTION: "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(ins->sub));
+// fprintf(stdout,"SOURCE REGISTER: "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(ins->rs));
+// fprintf(stdout,"OPERAND REGISTER: "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(ins->rt));
+// fprintf(stdout,"DESTINATION REGISTER: "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(ins->rd));
+// fprintf(stdout,"IMMEDIATE: "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(ins->imm));
+// fprintf(stdout, "\n");
+//}
diff --git a/src/interconnect.c b/src/interconnect.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../include/interconnect.h"
+#include "../include/bios.h"
+#include "../include/mem.h"
+#include "../include/util.h"
+#include "../include/types.h"
+#include "../include/defs.h"
+
+Interconnect*
+new_interconnect(void) {
+ Interconnect* inter = (Interconnect*)malloc(sizeof(Interconnect));
+ inter->BIOS = BIOS_new("roms/scph1001.bin");
+ inter->RAM = RAM_new();
+ return inter;
+}
+
+u32
+INTER_load32(Interconnect* inter, u32 addr)
+{
+ u32 offset = 0;
+
+ if (addr % 4 != 0) fprintf(stderr, "Unaligned_load32_address: %08X", addr);
+
+ /* Assert address Mappings */
+ offset = UTIL_contains(BIOS_START, BIOS_SIZE, addr);
+ if (offset != -1)
+ return BIOS_load32(inter->BIOS, offset);
+
+ offset = UTIL_contains(RAM_START, RAM_SIZE, addr);
+ if (offset != -1)
+ return RAM_load32(inter->RAM, offset);
+
+ PANIC("Unhandled Load32 At Address %08X\n", addr);
+}
+
+void
+INTER_store32(Interconnect* inter, u32 addr, u32 val)
+{
+ u32 offset = 0;
+
+ if (addr % 4 != 0)
+ fprintf(stderr, "Unaligned_store32_address: %08X", addr);
+
+ offset = UTIL_contains(RAM_START, RAM_SIZE, addr);
+ if (offset != -1)
+ {
+ fprintf(stdout, "Ignoring RAM write; %X\n", addr);
+ return;
+ }
+
+ offset = UTIL_contains(RAM_SIZE_START, RAM_SIZE_SIZE, addr);
+ if (offset != -1)
+ {
+ fprintf(stdout, "Ignoring RAM_SIZE register write %X\n", addr);
+ return;
+ }
+
+ offset = UTIL_contains(CACHECONTROL_START, CACHECONTROL_SIZE, addr);
+ if (offset != -1)
+ {
+ fprintf(stdout, "Ignoring CACHECONTROL address write: %X\n", addr);
+ return;
+ }
+
+ offset = UTIL_contains(SYSCONTROL_START, SYSCONTROL_SIZE, addr);
+ if (offset != -1)
+ {
+ switch(offset) {
+ case 0:
+ if (val != 0x1F000000) {
+ fprintf(stderr, "Bad Expansion 1 base address: %08X", val);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 4:
+ if (val != 0x1F802000) {
+ fprintf(stderr, "Bad expansion 2 base address: %08X", val);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ default:
+ fprintf(stderr, "Unhandled write to SYSCONTROL register\n");
+ return;
+ }
+ return;
+ }
+
+ PANIC("Unhandled store 32 into address: %08X\n", addr);
+}
diff --git a/src/main.c b/src/main.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../include/types.h"
+#include "../include/cpu.h"
+#include "../include/interconnect.h"
+#include "../include/bios.h"
+#include "../include/mem.h"
+#include "../include/defs.h"
+
+int
+main(int argc, char **argv)
+{
+ CPU* cpu;
+ Interconnect* inter;
+
+ inter = new_interconnect();
+ cpu = new_cpu(inter);
+
+ while(1) {
+ CPU_run_next_instruction(cpu);
+ }
+
+ //free(inter->BIOS->data);
+ //free(inter->BIOS);
+ //free(inter->RAM->data);
+ //free(inter->RAM);
+ //free(inter);
+ //free(cpu);
+
+
+ return 0;
+}
diff --git a/src/mem.c b/src/mem.c
@@ -0,0 +1,39 @@
+#include <stdlib.h>
+#include <string.h>
+#include "../include/mem.h"
+#include "../include/types.h"
+#include "../include/util.h"
+
+RAM*
+RAM_new(void)
+{
+ RAM* ram = (RAM*)(malloc(sizeof(RAM)));
+ ram->data = (u8*)(malloc(sizeof(u8) * RAM_SIZE));
+
+ memset(ram->data, 0xca, RAM_SIZE);
+ return ram;
+}
+
+u32
+RAM_load32(RAM* r, u32 offset)
+{
+ return (r->data[offset + 3] << 24) |
+ (r->data[offset + 2] << 16) |
+ (r->data[offset + 1] << 8) |
+ (r->data[offset + 0]);
+}
+
+void
+RAM_store32(RAM* r, u32 offset, u32 val)
+{
+ u8 b0 = val;
+ u8 b1 = (val >> 8);
+ u8 b2 = (val >> 16);
+ u8 b3 = (val >> 24);
+
+ r->data[offset + 0] = b0;
+ r->data[offset + 1] = b1;
+ r->data[offset + 2] = b2;
+ r->data[offset + 3] = b3;
+}
+
diff --git a/src/tags b/src/tags
@@ -0,0 +1,17 @@
+BIOS_load32 bios.c /^BIOS_load32(BIOS* b, u32 offset)$/
+CPU_decode_and_execute cpu.c /^CPU_decode_and_execute(CPU* cpu, instruction* i)$/
+CPU_run_next_instruction cpu.c /^CPU_run_next_instruction(CPU* cpu)$/
+INTER_load32 interconnect.c /^INTER_load32(Interconnect* inter, u32 addr)$/
+INTER_store32 interconnect.c /^INTER_store32(Interconnect* inter, u32 addr, u32 v/
+Mmain main.c /^main(int argc, char **argv)$/
+RAM_load32 mem.c /^RAM_load32(RAM* r, u32 offset)$/
+RAM_store32 mem.c /^RAM_store32(RAM* r, u32 offset, u32 val)$/
+UTIL_contains util.c /^UTIL_contains(u8 range, u32 addr)$/
+new_bios bios.c /^new_bios(char* path)$/
+new_cpu cpu.c /^new_cpu(Interconnect* inter) {$/
+new_instr cpu.c /^new_instr(u32 i)$/
+new_interconnect interconnect.c /^new_interconnect(void) {$/
+new_ram mem.c /^new_ram(void) $/
+print_instr cpu.c /^print_instr(instruction *ins)$/
+reg cpu.c /^reg(CPU* cpu, u32 reg) $/
+set_reg cpu.c /^set_reg(CPU* cpu, u32 reg, u32 val)$/
diff --git a/src/util.c b/src/util.c
@@ -0,0 +1,8 @@
+#include "../include/util.h"
+#include "../include/types.h"
+
+u32
+UTIL_contains(u32 start, u32 length, u32 addr)
+{
+ return (addr >= start && addr < start + length) ? addr-start : -1;
+}
diff --git a/test.c b/test.c
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+
+struct foo {
+ int pc;
+ int ra;
+};
+
+void
+bar(struct foo *foo1)
+{
+ foo1->pc +=1;
+}
+
+
+int
+main()
+{
+ struct foo foo1 = { 1,1 };
+ printf("%d", foo1.pc);
+ bar(&foo1);
+ printf("%d", foo1.pc);
+}
+