WSMan rev.7

Bandai WonderSwan series - Technical Information
Last update: 17 August 2016, 02:18:30 UTC

WonderSwan Reference Accessory Reference Miscellaneous Reference
Overview
System Overview
Parts
Memory Map
I/O Map

Hardware Programming
Display Controller
Sound
Keypad
System Controller
Interrupts
Serial Port
Internal EEPROM
DMA Controller
Sound DMA Controller
Timers

Other
Code Layout
WSR Format

Cartridge
Overview
Metadata
Banking
Real-Time Clock
EEPROM
General-Purpose Outputs

WonderWitch
Overview
Update Encryption
Flash ROM
I/O Ports

WonderGate
Overview
Terminology
Interface
Commands

V30MZ CPU
CPU Overview
CPU Instruction Set
CPU Instruction Encoding

Pinouts
ASWAN
SPHINX
SPHINX2
Ext. Port
Cart Connector
Cart Mapper
Cart Power Controller
Cart ROM
Cart SRAM

Related Information
Patents
CAIRO

Game List

About WSMan
About This Document

In this document, generally WonderSwan refers to WonderSwan and Pocket Challenge V2, and WonderSwan Color refers to WonderSwan Color and SwanCrystal, unless otherwise mentioned.

System Overview

WonderSwan

SoC: ASWAN Model: SW-001 PCB ID: PTE0021C / GMPI-S5

WonderSwan (WS) is the first generation of WonderSwan.

WonderSwan Color

SoC: SPHINX Model: WSC-001 PCB ID: PTS-0125B

WonderSwan Color (WSC) is the second generation of WonderSwan, adding colors, quadrupling the RAM, and adding several useful hardware features for developers.

SwanCrystal

SoC: SPHINX2 Model: SCT-001 PCB ID: ?

SwanCrystal (SC) is the third (and last) generation of WonderSwan, improving visibility and clarity with a superior display. There are no other differences in terms of capabilities.

Pocket Challenge V2

SoC: ASWAN Model: 3AA902 PCB ID: IM-M2

Pocket Challenge V2 (PC2) is an edutainment system released by Benesse, using the same ASWAN SoC in the original WonderSwan. The story about how this came to be is unknown to me. According to Koto's website, they did the hardware and software design of the console.

Due to using the same SoC as WonderSwan, the hardware is nearly identical aside from differences in the input layout. It's even possible to run WS games on the PC2, and vice-versa.

Specifications

SPHINX refers to both SPHINX and SPHINX2 unless mentioned.

ASWAN refers to both ASWAN and CAIRO unless mentioned.

Compatibility modes are not covered here, look at the respective sections for information on that.

CPU ASWAN: NEC V30MZ @ 3.072MHz (80186 compatible) SPHINX: NEC V30MZ @ 3.072MHz (80186 compatible) CAIRO: NEC V30MZ @ 6.144MHz (80186 compatible) BIOS ROM ?? RAM ASWAN: 16KB on-chip SRAM (8K x 16) @ 12.288MHz ? SPHINX: 64KB on-chip SRAM (32K x 16) @ 12.288MHz ? CAIRO: ?? Screen WS: 58mm x 37mm (2.7 inch FSTN LCD display) (TODO: Check) WSC: 58mm x 37mm (2.7 inch CSTN LCD display) SC: 58mm x 37mm (2.7 inch TFT color LCD display) (TODO: Check) PC2: Same as WS SCR Layers 2 layers, 32x32 tiles SPR Count Up to 128 SPRs per frame, 32 per line Colors (ASWAN) 16 palettes of 4 colors 0~15 may be used by SCR. 8~15 may be used by SPR. 0~3 and 8~11 have color 0 opaque. 4~7 and 12~15 have color 0 transparent. Colors (SPHINX) 16 palettes of 16 colors 0~15 may be used by SCR. 8~15 may be used by SPR. Color 0 is opaque. Priorities SCR1 < SPR low priority < SCR2 < SPR high priority SPR127 < SPR0 Sound 4 32-sample 4-bit wave channels Channel 2 may emit PCM voice Channel 3 may have Sweep feature Channel 4 may emit Noise SPHINX: Additional headphone-only PCM channel Sound Output Built-in Speaker (mono) 24kHz sample rate? Unsigned 8-bit PWM? Headphone accessory (stereo) 24kHz sample rate Signed 16-bit DAC Game Pad 2 sets of 4-button directionals, 3 buttons PC2: 4-button directional, 4 buttons Expansion Full-duplex serial port Headphone sound Cart (BMC2001) Up to 128Mbit ROM Up to 128Mbit SRAM Up to 16Kbit EEPROM Cart (BMC2003) Up to 512Mbit ROM Up to 128Mbit SRAM Up to 4 general-purpose output lines Supports RTC Cart (KARNAK) ? Power 1 AA battery

Parts

Console Parts

Bandai SPGY-1001 ASWAN SoC for WonderSwan --- Bandai SPGY-1001 ASWAN SoC for Pocket Challenge V2 --- Bandai SPGY-1002 SPHINX SoC for WonderSwan Color --- Bandai SPGY-1003 SPHINX2 SoC for SwanCrystal --- CSI 93C86S EEPROM in WonderSwan Color ---

Cart Parts

Bandai 2001 Mapper + I/O controller --- Bandai 2003 Mapper + I/O controller --- Koto KARNAK Mapper + I/O controller --- Koto GIZA Power Controller --- Seiko S-3511A Real-time Clock --- BSI BS62LV256TC-70 SRAM --- Seiko S-29530 16Kbit EEPROM --- Fujitsu 29DL400TC-90PFTN WonderWitch Flash ROM --- NEC D442000LGU-B85X-9JH WonderWitch SRAM ---

Accessory Parts

Rohm BU9480F Headphone adapter DAC --- Rohm 2SK3541 Headphone adapter Amplifier --- Suntac D825256GC001 WonderGate SoC --- Micron M29W800AT WonderGate Flash ROM --- Cypress CY7C1021V33L-12ZC WonderGate SRAM ---

Memory Map

Address Content Bus Access Time 000000h-00FFFFh* Internal RAM 16-bit 1 cycle 010000h-01FFFFh Cartridge SRAM 8-bit 1/3 cycles* 020000h-02FFFFh Cartridge ROM bank 0 16-bit 1 cycle 030000h-03FFFFh Cartridge ROM bank 1 16-bit 1 cycle 040000h-0FFFFFh Cartridge ROM bank 2 16-bit 1 cycle

Internal RAM ends at 003FFFh for WonderSwan. Reading an unmapped area returns 090h, and writes have no effect. WonderSwan Color and SwanCrystal fill all of the 64KB region.

Cartridge SRAM is 3 cycles on WonderSwan and Color in WS mode. It is 1 cycle on a Color unit in any color mode.

Mapping Specifics

The entire space from 010000h onwards is just sent directly to the cart, and the cart handles banking the ROM and the SRAM access and such. All WonderSwan carts use this mapping layout.

Only Internal RAM and Cartridge RAM areas may be written to. Writes to Cartridge ROM areas are not emitted. This is enforced by the SoC itself, rather than the cart mapper.

Address Overflow

It is possible to attempt to access beyond the 20-bit address space by abusing segmentation. Since the CPU lacks an A20 line, these will just wrap around to the beginning of the address map.

Endian

The CPU uses little-endian memory format. Thus, when accessing 16-bit or 32-bit data in memory, the least significant byte is the first byte, and the most significant the last. This is the same as other x86 CPUs, Z80, and others.

Memory Clocking

I believe the internal SRAM is clocked at the full 12.288MHz input clock, and then split into 4 "access slots" to allow for seemingly-simultaneous access by peripherals without stalling. The order of these access slots is unsubstantiated and a complete guess. It is likely to somewhat matter though, as it can affect very aggressive palette RAM tricks. The actual usage of each slot is educated guesses based on the requirements of the individual units.

0 CPU, DMA, Sprite DMA 1 Sound Wavetable (and sound DMA?) 2 SCR tiles, SCR tilemaps 3 Palette RAM

CPU and DMA must share a slot, as the DMA engine pauses the CPU and runs at a speed that is unlikely to be any rate other than /4. Sprite DMA appears to pause the CPU as well, so it's likely that it also shares the slot.

Sound wavetable must have its own slot, otherwise it could not run at /4 without stalls. Likely, the sound hardware reads 16-bit words in round robin (ch1, ch2, ch3, ch4) into separate buffers every cycle and shifts out the data (since each sample is 4-bit, it takes 4 cycles to exhaust a full 16-bit word). This would also explain the start-up time for the sound hardware (it must load all the buffers before starting, to prevent outputting garbage).

SCR tiles and tilemaps are likely to have their own slot, since it is impossible to detect any CPU stalling from the access. Whether the data is copied out at some point by a DMA engine is unknown, more tests must be performed, therefore the timing behavior for this is unknown.

Palette RAM must have its own slot, as the pixel clock is /4. Every cycle, a 16-bit word is read from the palette RAM and then output to the screen.

I/O Map

000h RW REG_DISP_CTRL 001h RW REG_BACK_COLOR 002h R REG_LINE_CUR 003h RW REG_LINE_CMP 004h RW REG_SPR_BASE 005h RW REG_SPR_FIRST 006h RW REG_SPR_COUNT 007h RW REG_MAP_BASE 008h RW REG_SCR2_WIN_X0 009h RW REG_SCR2_WIN_Y0 00Ah RW REG_SCR2_WIN_X1 00Bh RW REG_SCR2_WIN_Y1 00Ch RW REG_SPR_WIN_X0 00Dh RW REG_SPR_WIN_Y0 00Eh RW REG_SPR_WIN_X1 00Fh RW REG_SPR_WIN_Y1 010h RW REG_SCR1_X 011h RW REG_SCR1_Y 012h RW REG_SCR2_X 013h RW REG_SCR2_Y 014h RW REG_LCD_CTRL 015h RW REG_LCD_ICON 016h RW REG_LCD_VTOTAL 017h RW REG_LCD_VSYNC 018h -- --- 019h -- --- 01Ah ?? ??? 01Bh -- --- 01Ch RW REG_PALMONO_POOL_0 01Dh RW REG_PALMONO_POOL_1 01Eh RW REG_PALMONO_POOL_2 01Fh RW REG_PALMONO_POOL_3 020h RW REG_PALMONO_0 (Low) 021h RW REG_PALMONO_0 (High) 022h RW REG_PALMONO_1 (Low) 023h RW REG_PALMONO_1 (High) 024h RW REG_PALMONO_2 (Low) 025h RW REG_PALMONO_2 (High) 026h RW REG_PALMONO_3 (Low) 027h RW REG_PALMONO_3 (High) 028h RW REG_PALMONO_4 (Low) 029h RW REG_PALMONO_4 (High) 02Ah RW REG_PALMONO_5 (Low) 02Bh RW REG_PALMONO_5 (High) 02Ch RW REG_PALMONO_6 (Low) 02Dh RW REG_PALMONO_6 (High) 02Eh RW REG_PALMONO_7 (Low) 02Fh RW REG_PALMONO_7 (High) 030h RW REG_PALMONO_8 (Low) 031h RW REG_PALMONO_8 (High) 032h RW REG_PALMONO_9 (Low) 033h RW REG_PALMONO_9 (High) 034h RW REG_PALMONO_A (Low) 035h RW REG_PALMONO_A (High) 036h RW REG_PALMONO_B (Low) 037h RW REG_PALMONO_B (High) 038h RW REG_PALMONO_C (Low) 039h RW REG_PALMONO_C (High) 03Ah RW REG_PALMONO_D (Low) 03Bh RW REG_PALMONO_D (High) 03Ch RW REG_PALMONO_E (Low) 03Dh RW REG_PALMONO_E (High) 03Eh RW REG_PALMONO_F (Low) 03Fh RW REG_PALMONO_F (High) 040h RW REG_DMA_SRC (Low) 041h RW REG_DMA_SRC (Mid) 042h RW REG_DMA_SRC_HI 043h -- --- 044h RW REG_DMA_DST (Low) 045h RW REG_DMA_DST (High) 046h RW REG_DMA_LEN (Low) 047h RW REG_DMA_LEN (High) 048h RW REG_DMA_CTRL 049h -- --- 04Ah RW REG_SDMA_SRC (Low) 04Bh RW REG_SDMA_SRC (Mid) 04Ch RW REG_SDMA_SRC_HI 04Dh -- --- 04Eh RW REG_SDMA_LEN (Low) 04Fh RW REG_SDMA_LEN (Mid) 050h RW REG_SDMA_LEN (High) 051h -- --- 052h RW REG_SDMA_CTRL 053h -- --- 054h -- --- 055h -- --- 056h -- --- 057h -- --- 058h -- --- 059h -- --- 05Ah -- --- 05Bh -- --- 05Ch -- --- 05Dh -- --- 05Eh -- --- 05Fh -- --- 060h RW REG_DISP_MODE 061h -- --- 062h RW REG_WSC_SYSTEM 063h -- --- 064h -- --- 065h -- --- 066h -- --- 067h -- --- 068h -- --- 069h -- --- 06Ah RW REG_HYPER_CTRL 06Bh RW REG_HYPER_CHAN_CTRL 06Ch -- --- 06Dh -- --- 06Eh -- --- 06Fh -- --- 070h R REG_UNK_70 071h R REG_UNK_71 072h R REG_UNK_72 073h R REG_UNK_73 074h R REG_UNK_74 075h R REG_UNK_75 076h R REG_UNK_76 077h R REG_UNK_77 078h -- --- 079h -- --- 07Ah -- --- 07Bh -- --- 07Ch -- --- 07Dh -- --- 07Eh -- --- 07Fh -- --- 080h RW REG_SND_CH1_PITCH (Low) 081h RW REG_SND_CH1_PITCH (High) 082h RW REG_SND_CH2_PITCH (Low) 083h RW REG_SND_CH2_PITCH (High) 084h RW REG_SND_CH3_PITCH (Low) 085h RW REG_SND_CH3_PITCH (High) 086h RW REG_SND_CH4_PITCH (Low) 087h RW REG_SND_CH4_PITCH (High) 088h RW REG_SND_CH1_VOL 089h RW REG_SND_CH2_VOL 08Ah RW REG_SND_CH3_VOL 08Bh RW REG_SND_CH4_VOL 08Ch RW REG_SND_SWEEP_VALUE 08Dh RW REG_SND_SWEEP_TIME 08Eh RW REG_SND_NOISE 08Fh RW REG_SND_WAVE_BASE 090h RW REG_SND_CTRL 091h RW REG_SND_OUTPUT 092h R REG_SND_RANDOM (Low) 093h R REG_SND_RANDOM (High) 094h RW REG_SND_VOICE_CTRL 095h RW REG_SND_HYPERVOICE 096h RW REG_SND_9697 (Low) 097h RW REG_SND_9697 (High) 098h RW REG_SND_9899 (Low) 099h RW REG_SND_9899 (High) 09Ah R REG_SND_9A 09Bh R REG_SND_9B 09Ch R REG_SND_9C 09Dh R REG_SND_9D 09Eh R REG_SND_9E 09Fh -- --- 0A0h RW REG_HW_FLAGS 0A1h -- --- 0A2h RW REG_TMR_CTRL 0A3h ?? ??? 0A4h RW REG_HTMR_FREQ (Low) 0A5h RW REG_HTMR_FREQ (High) 0A6h RW REG_VTMR_FREQ (Low) 0A7h RW REG_VTMR_FREQ (High) 0A8h R REG_HTMR_CTR (Low) 0A9h R REG_HTMR_CTR (High) 0AAh R REG_VTMR_CTR (Low) 0ABh R REG_VTMR_CTR (High) 0ACh ?? ??? 0ADh -- --- 0AEh -- --- 0AFh -- --- 0B0h RW REG_INT_BASE 0B1h RW REG_SER_DATA 0B2h RW REG_INT_ENABLE 0B3h RW REG_SER_STATUS 0B4h R REG_INT_STATUS 0B5h RW REG_KEYPAD 0B6h W REG_INT_ACK 0B7h ?? ??? 0B8h -- --- 0B9h -- --- 0BAh RW REG_IEEP_DATA (Low) 0BBh RW REG_IEEP_DATA (High) 0BCh RW REG_IEEP_ADDR (Low) 0BDh RW REG_IEEP_ADDR (High) 0BEh R REG_IEEP_STATUS 0BEh W REG_IEEP_CMD 0BFh ?? ??? 0C0h RW REG_BANK_ROM2 0C1h RW REG_BANK_SRAM 0C2h RW REG_BANK_ROM0 0C3h RW REG_BANK_ROM1 0C4h RW REG_EEP_DATA (Low) 0C5h RW REG_EEP_DATA (High) 0C6h RW REG_EEP_ADDR (Low) 0C7h RW REG_EEP_ADDR (High) 0C8h R REG_EEP_STATUS 0C8h W REG_EEP_CMD 0C9h ?? ??? 0CAh R REG_RTC_STATUS 0CAh W REG_RTC_CMD 0CBh RW REG_RTC_DATA 0CCh RW REG_GPO_EN 0CDh RW REG_GPO_DATA 0CEh RW REG_WW_FLASH_CE 0CFh ?? ??? 0D0h ?? ??? 0D1h ?? ??? 0D2h ?? ??? 0D3h ?? ??? 0D4h ?? ??? 0D5h ?? ??? 0D6h ?? ??? 0D7h ?? ??? 0D8h ?? ??? 0D9h ?? ??? 0DAh ?? ??? 0DBh ?? ??? 0DCh ?? ??? 0DDh ?? ??? 0DEh ?? ??? 0DFh ?? ??? 0E0h ?? ??? 0E1h ?? ??? 0E2h ?? ??? 0E3h ?? ??? 0E4h ?? ??? 0E5h ?? ??? 0E6h ?? ??? 0E7h ?? ??? 0E8h ?? ??? 0E9h ?? ??? 0EAh ?? ??? 0EBh ?? ??? 0ECh ?? ??? 0EDh ?? ??? 0EEh ?? ??? 0EFh ?? ??? 0F0h ?? ??? 0F1h ?? ??? 0F2h ?? ??? 0F3h ?? ??? 0F4h ?? ??? 0F5h ?? ??? 0F6h ?? ??? 0F7h ?? ??? 0F8h ?? ??? 0F9h ?? ??? 0FAh ?? ??? 0FBh ?? ??? 0FCh ?? ??? 0FDh ?? ??? 0FEh ?? ??? 0FFh ?? ???

Mapping Specifics

Only the bottom 8 bits of the port address should be used. The top 8 bits do some really weird stuff, described below.

The entire 0C0h ~ 0FFh space is just sent directly to the cart, and the cart handles all of it.

Unmapped areas

Actually unmapped areas return 090h on WonderSwan only. On WonderSwan Color and SwanCrystal previously unmapped areas were mapped to a simple return 00h. Unmapped registers are denoted in the above table with ---, registers that are wired to zero even on WS are listed as zero. (TODO: I haven't gone through to do this yet)

Top 8 bits

Most registers mirror every 0200h ports, but some do no mirroring. Registers that do no mirroring have a peculiar behavior where if either of the top 2 bits of the port address are non-zero, even "zero mapped" registers on WSC/SC are unmapped.

As far as I can tell, the "not mirrored" area of 0100h ~ 01FFh is wired to return 00h.

(TODO: Check on original WS)

Display Controller

WonderSwan has a display resolution of 224x144.

Display Hardware

The WonderSwan series used 3 types of LCD display throughout its lifetime.

The original WonderSwan used a monochrome FSTN (filtered super-twisted nematic) LCD display capable of displaying 16 shades of grey.

The WonderSwan Color used a CSTN (color super-twisted nematic) LCD display capable of displaying 12-bit color (4096 colors).

The SwanCrystal used a TFT (thin film transistor) LCD display also capable of displaying 12-bit color. The superior viewing characteristics of the TFT technology makes it the superior system in terms of visibility.

Display Timing

The (basic) display timing is something like this:

0 224 256 ----------------- 0| | | | | | | | | | | | 144|-------------- | 159|_________________| PIXCLK = 3.072MHz HDISP = 224 HBLANK = 32 HTOTAL = 256 HCLK = 12kHz (3072000 / 256) VDISP = 144 VBLANK = 15 VTOTAL = 159 VCLK = ~75.47Hz (12000 / 159)

The CPU is not paused while the display controller accesses memory. See the Memory Clocking section for more information.

Sprite DMA seems to happen on LINE_CUR = 142 (.5?). The DMA probably ends right at the start of V-Blank. This might have been done so that it acts like DMA at V-Blank, but without eating into V-Blank CPU cycles? In any case, common emulator behavior of instant DMA to the current source information at line 142 is incorrect and causes tearing.

Palettes

Depending on the current video mode, as selected by REG_DISP_MODE, different sets of palette data are used.

Monochrome

Palettes in the monochrome video modes are controlled by the REG_PALMONO_POOL registers, and the REG_PALMONO registers.

REG_PALMONO_POOL decides the pool of 8 colors that are then picked from to decide the final palettes. These colors are 4-bit, where 00h is brightest and 0Fh is darkest.

The REG_PALMONO registers choose 4 colors for each of the 16 palettes from this 8-color pool.

Palettes 0-3 and 8-11 are entirely opaque, none of the colors will be used for transparency. Palettes 4-7 and 12-15 use color 0 as transparency, and these colors will never be displayed.

Color

Palettes in the color video modes completely ignore the monochrome palette registers, instead storing the palettes in RAM.

In these modes, the palettes are stored in RAM at 0FE00h, 1 word per color, 16 colors per palette. In 2BPP modes, the latter 12 colors in each palette can only be accessed by the background color (as the tile data can only address the first 4 colors).

All palettes have color 0 as transparency, and these colors will not be displayed unless used as the background color in REG_BACK_COLOR.

Color entry format:

8-11 Red 4-7 Green 0-3 Blue

Tiles

The tile format and placement in memory is different depending on the current video mode, selected by REG_DISP_MODE. All tiles are 8x8.

2BPP Tiles

Tiles are located at 02000h in RAM. On original WS and compatiblity mode, only 0200h tiles may be stored here. On a color mode, up to 0400h tiles may be stored here. Sprites may only use the first 0200h tiles; the top 0200h tiles may only be used by SCR, using an attribute bit in each tile's entry.

Each tile occupies 16 bytes.

2BPP Planar Format

In this format, each byte contains a full 8 pixel row, defining a single bit of the resulting pixels. Even bytes determine bit0, odd bytes determine bit1.

Each bit: MSb LSb [x+7][x+6][x+5][x+4][x+3][x+2][x+1][x+0]

Each byte: LSB MSB [y+0 b0][y+0 b1] [y+1 b0][y+1 b1] [y+2 b0][y+2 b1] [y+3 b0][y+3 b1] [y+4 b0][y+4 b1] [y+5 b0][y+5 b1] [y+6 b0][y+6 b1] [y+7 b0][y+7 b1]

2BPP Packed Format

In this format, each byte contains all bits for 4 pixels of the pixel row. Even bytes determine the left pixels, odd bytes determine the right pixels.

Each bit: MSb LSb [x+3 b1][x+3 b0][x+2 b1][x+2 b0][x+1 b1][x+1 b0][x+0 b1][x+0 b0]

Each byte: LSB MSB [y+0 x+0][y+0 x+4] [y+1 x+0][y+1 x+4] [y+2 x+0][y+2 x+4] [y+3 x+0][y+3 x+4] [y+4 x+0][y+4 x+4] [y+5 x+0][y+5 x+4] [y+6 x+0][y+6 x+4] [y+7 x+0][y+7 x+4]

4BPP Tiles

Tiles are located at 04000h in RAM, and up to 0400h tiles may be stored here. Sprites may only use the first 0200h tiles; the top 0200h tiles may only be used by SCR, using an attribute bit in each tile's entry.

Each tile occupies 32 bytes.

4BPP Planar Format

In this format, each byte contains a full 8 pixel row, defining a single bit of the resulting pixels. In order, bytes determine bit0, bit1, bit2, bit3.

Each bit: MSb LSb [x+7][x+6][x+5][x+4][x+3][x+2][x+1][x+0]

Each byte: LSB MSB [y+0 b0][y+0 b1][y+0 b2][y+0 b3] [y+1 b0][y+1 b1][y+1 b2][y+1 b3] [y+2 b0][y+2 b1][y+2 b2][y+2 b3] [y+3 b0][y+3 b1][y+3 b2][y+3 b3] [y+4 b0][y+4 b1][y+4 b2][y+4 b3] [y+5 b0][y+5 b1][y+5 b2][y+5 b3] [y+6 b0][y+6 b1][y+6 b2][y+6 b3] [y+7 b0][y+7 b1][y+7 b2][y+7 b3]

4BPP Packed Format

In this format, each byte contains all bits for 2 pixels of the pixel row. In order, bytes determine left-most, left-center, right-center, right-most pixels.

Each bit: MSb LSb [x+1 b3][x+1 b2][x+1 b1][x+1 b0][x+0 b3][x+0 b2][x+0 b1][x+0 b0]

Each byte: LSB MSB [y+0 x+0][y+0 x+2][y+0 x+4][y+0 x+6] [y+1 x+0][y+1 x+2][y+1 x+4][y+1 x+6] [y+2 x+0][y+2 x+2][y+2 x+4][y+2 x+6] [y+3 x+0][y+3 x+2][y+3 x+4][y+3 x+6] [y+4 x+0][y+4 x+2][y+4 x+4][y+4 x+6] [y+5 x+0][y+5 x+2][y+5 x+4][y+5 x+6] [y+6 x+0][y+6 x+2][y+6 x+4][y+6 x+6] [y+7 x+0][y+7 x+2][y+7 x+4][y+7 x+6]

Screens

WonderSwan has 2 scrollable tilemapped screens each organized as a 32x32 map of tiles. The two screens are commonly referred to as SCR1 and SCR2. SCR1 is always behind SCR2.

SCR2 has a window function that can be configured to either display only the region inside the window, or only the region outside of it. This window can be configured with the REG_SCR2_WIN registers.

The location in memory of the tile maps can be configured using REG_MAP_BASE.

Data Format

Each tile's entry in a tile map is defined with a 16-bit word.

15 Vertical flip 14 Horizontal flip 13 Tile bank (WSC only) 9-12 Palette 0-8 Tile

Sprites

Maximum 128 sprites, 32 per scanline. Sprite data location in memory can be moved with REG_SPR_BASE. The sprite to begin processing with can be changed using REG_SPR_FIRST. The number of sprites to process can be changed with REG_SPR_COUNT.

All sprites appear above SCR1, and there is a flag for whether the sprite will appear above SCR2.

Sprite drawing puts priority to earlier sprites in the list. It is currently unknown what happens with a sprite with SCR2 Priority overlapping a sprite with a lower index. (TODO)

Sprites support being clipped by a window defined with the REG_SPR_WIN registers. Each sprite has a flag to designate if it will only draw inside or outside of the window. Sprite window can be disabled universally as well.

Sprites also support being horizontally and vertically flipped.

Sprites are drawn per-line, but the sprite RAM area is copied out on display line 142, preventing sprite multiplexing with raster effects.

As the sprite data format only allows 8 palettes, the actual selected palette is +8. So palette 03h for sprites is actually palette 0Bh.

Data Format

Each sprite's entry in the sprite table uses a 32-bit dword.

24-31 X position 16-23 Y position 15 Vertical flip 14 Horizontal flip 13 SCR2 priority 12 Window clip mode (0=Display Outside, 1=Inside) 9-11 Palette 0-8 Tile

Windows

TODO

Ports

REG_DISP_CTRL

Port: 000h Access: RW Size: Byte Mask: 00******

Display control.

5 SCR2 window enable 4 SCR2 window mode (0=Display Inside, 1=Outside) 3 SPR window enable 2 SPR enable 1 SCR2 enable 0 SCR1 enable

REG_BACK_COLOR

Port: 001h Access: RW Size: Byte Mask: 00000*** (WS mode) ******** (WSC mode)

Determines the color used for pixels uncovered by sprites and screens.

Mono: 0-2 Background color (pool index) Color: 4-7 Background color palette 0-3 Background color index

REG_LINE_CUR

Port: 002h Access: R Size: Byte Mask: ********

Current line being displayed.

REG_LINE_CMP

Port: 003h Access: RW Size: Byte Mask: ********

Line to fire HWINT_LINE on, compared against REG_LINE_CUR.

REG_SPR_BASE

Port: 004h Access: RW Size: Byte Mask: 000***** (WS mode) 00****** (WSC mode)

The base address of the sprite table. Register value should be address >> 9.

REG_SPR_FIRST

Port: 005h Access: RW Size: Byte Mask: 0*******

The index of the first sprite to draw. TODO: What happens if FIRST+COUNT is > 080h? I believe it drops the extra sprites just like COUNT > 080h, yes?

REG_SPR_COUNT

Port: 006h Access: RW Size: Byte Mask: ********

The number of sprites to draw. Any value above 080h acts as 080h.

REG_MAP_BASE

Port: 007h Access: RW Size: Byte Mask: 0***0*** (WS mode) ******** (WSC mode)

The base address of the tile maps.

4-7 SCR2 base address >> 11 0-3 SCR1 base address >> 11

REG_SCR2_WIN_X0

Port: 008h Access: RW Size: Byte Mask: ********

Top-left X of SCR2 Window.

REG_SCR2_WIN_Y0

Port: 009h Access: RW Size: Byte Mask: ********

Top-left Y of SCR2 Window.

REG_SCR2_WIN_X1

Port: 00Ah Access: RW Size: Byte Mask: ********

Bottom-right X of SCR2 Window.

REG_SCR2_WIN_Y1

Port: 00Bh Access: RW Size: Byte Mask: ********

Bottom-right Y of SCR2 Window.

REG_SPR_WIN_X0

Port: 00Ch Access: RW Size: Byte Mask: ********

Top-left X of SPR Window.

REG_SPR_WIN_Y0

Port: 00Dh Access: RW Size: Byte Mask: ********

Top-left Y of SPR Window.

REG_SPR_WIN_X1

Port: 00Eh Access: RW Size: Byte Mask: ********

Bottom-right X of SPR Window.

REG_SPR_WIN_Y1

Port: 00Fh Access: RW Size: Byte Mask: ********

Bottom-right Y of SPR Window.

REG_SCR1_X

Port: 010h Access: RW Size: Byte Mask: ********

SCR1 X scroll.

REG_SCR1_Y

Port: 011h Access: RW Size: Byte Mask: ********

SCR1 Y scroll.

REG_SCR2_X

Port: 012h Access: RW Size: Byte Mask: ********

SCR2 X scroll.

REG_SCR2_Y

Port: 013h Access: RW Size: Byte Mask: ********

SCR2 Y scroll.

REG_LCD_CTRL

Port: 014h Access: RW Size: Byte Mask: ******** (WS) ****00** (WSC) 0000000* (SC)

LCD control.

1-7 System-specific 0 LCD sleep (0=Sleep, 1=Active) WonderSwan: 1-7 ??? (TODO) WonderSwan Color: 4-7 Holds state, does nothing? 1 Contrast (0=Low, 1=High) SwanCrystal: 1-7 Zero

REG_LCD_ICON

Port: 015h Access: RW Size: Byte Mask: 00******

LCD icons.

5 Auxiliary 3 (Big circle) 4 Auxiliary 2 (Medium circle) 3 Auxiliary 1 (Small circle) 2 Horizontal orientation indicator 1 Vertical orientation indicator 0 Sleep indicator

REG_LCD_VTOTAL

Port: 016h Access: RW Size: Byte Mask: ********

Display VTOTAL. This affects all video timings. The value here is 1 less than the value of VTOTAL. Initial value is 09Eh.

Setting this value to 255 causes the display to turn off. Setting this value to less than 143 will stop raising VBLANK interrupts, and will cause the first VTOTAL lines to repeat on the LCD.

On SwanCrystal, having this register set to an odd value will give the LCD a bad time. Noted effects: scanlines-looking effect, temporary burn-in, increased blurring. This only happens with an odd value, any even value looks fine.

REG_LCD_VSYNC

Port: 017h Access: RW Size: Byte Mask: ********

VSYNC line position? This register does not exist on SwanCrystal, it is a read-only zero-wired register there. Initial value is 09Bh.

This must be greater than 144 or less than VTOTAL or the display turns off (?).

Moving this value closer to active display improves LCD visibility. Moving it farther from active display reduces it.

TODO: I'm not entirely sure what this actually is lmao

REG_PALMONO_POOL

Port: 01Ch, 01Dh, 01Eh, 01Fh Access: RW Size: Byte Mask: ********

Monochrome palette pool selection.

4-7 Color (reg*2)+1 0-3 Color (reg*2)+0

REG_PALMONO

Port: 020h-021h, 022h-023h, 024h-025h, 026h-027h 028h-029h, 02Ah-02Bh, 02Ch-02Dh, 02Eh-02Fh 030h-031h, 032h-033h, 034h-035h, 036h-037h 038h-039h, 03Ah-03Bh, 03Ch-03Dh, 03Eh-03Fh Access: RW Size: Word Mask: 0***0*** 0***0***

Monochrome palettes

12-14 Color 3 8-10 Color 2 4-6 Color 1 0-2 Color 0

Sound

The sound hardware seems to take about 16 cycles to start up after some things, for some reason. (TODO) See the Memory Clocking section for speculation behind this.

Timing

Each sound channel updates every master clock (3072000 Hz). The sweep section updates every 256*32 clocks (375 Hz). The headphone DAC updates every 128 clocks (24000 Hz). The speaker PWM presumably is similar, but the PWM specifics are unknown (TODO?).

Pitch

Pitch register algorithm is:

reg = 2048 - (3072000 / 32 / f)

You may convert a register value back to a frequency with this algorithm:

f = 3072000 / 32 / (2048 - reg) Hz

These values are used with the REG_SND_CHx_PITCH registers.

This register is the down-counter compare value used for advancing to the next step in the sample. After each sample plays, the internal counter is reset to 2048, then decrements by 1 every master clock. Once the internal counter matches the pitch register, the next sample is output.

HyperVoice

TODO: Overview

On WonderSwan, these registers are unmapped. This holds true in WonderSwan mode on a WonderSwan Color or SwanCrystal.

Sweep

Each step in the sweep occurs every (reg+1) * 32*256 master clocks. In terms of real time, you can decide the sweep time register like this, where T is the time in milliseconds between each sweep step:

reg = (T / 2.667ms) - 1

This value is used for the REG_SND_SWEEP_TIME register.

PCM Voice

The PCM voice functionality on channel 2 uses its volume register REG_SND_CH2_VOL to provide raw 8-bit PCM data. This data can then be selected to stereo using REG_SND_VOICE_CTRL. Sample volume may be either full or 50%, as detailed in the description of REG_SND_VOICE_CTRL.

Noise

The noise functionality on channel 4 utilizes a 15-bit LFSR with a configurable tap. The LFSR update algorithm is:

noise_bit = (1 ^ (ctr >> 7) ^ (ctr >> tap)) & 1 ctr = (ctr << 1) | noise_bit

The configurable tap values are:

Mode Tap 0 14 1 10 2 13 3 4 4 8 5 6 6 9 7 11

Resetting noise sets the LFSR counter to 00000h. The LFSR updates while the enable bit is on and Channel 4 is on, even if Channel 4 is not in Noise mode. Some games hang up if the RNG continuously returns the same value with Channel 4 set to wave mode (Clock Tower notably).

The output of the noise channel is noise_bit as specified above, multiplied by 0Fh.

TODO: I'm not entirely sure that the outgoing bit is the output bit, but I think it is.

Sound Generation Specifics

This section describes the operation of the hardware used to produce sound. It is mostly of use for emulator authors, but some of the peculiarities might be useful to a developer. This data was obtained by attaching a logic analyzer to the Ext.Port, and writing many tests to check the serial sound data.

All sound generation is using unsigned integers. This means the sound output is heavily biased.

Sample Generation

For simple wave channels, the generated sample is L = wave[chan][ptr] * vol[chan].l ; R = wave[chan][ptr] * vol[chan].r. Volume is latched at each sample's generation, not when the wave pointer changes.

For noise channel, the generated sample is L = noise_bit * 0Fh * vol[chan].l ; R = noise_bit * 0Fh * vol[chan].r.

For voice channel, the generated sample is L = (voice_ctrl & 04h) ? vol[chan] : (voice_ctrl & 08h) ? vol[chan] >> 1 : 0 ; R = (voice_ctrl & 01h) ? vol[chan] : (voice_ctrl & 02h) ? vol[chan] >> 1 : 0.

The two accumulators (L and R) are signed 11-bit, and are calculated with a simple unsigned addition of all the samples.

HyperVoice Generation

TODO

This seems to only be possible to drive by using Sound DMA. When Sound DMA stops, output is halted as well.

Input samples are signed 8-bit.

Speaker Output

Speaker DAC is unsigned 8-bit.

TODO: How are L and R merged? Is this a real DAC, or an R2R ladder? What's the sample rate?

The output algorithm is (accum >> spkr_dac_shift) & 0FFh.

Headphone Output

Headphone DAC is a stereo signed 16-bit digital DAC (Rohm BU9480F), with a sample rate of 24000Hz.

For HyperVoice processing, each accumulator adds the HyperVoice data, with signed saturation at 03FFh and -0400h.

The accumulators are then expanded to signed 16-bits with a left shift by 5 bits.

Ports

REG_SND_CH1_PITCH

REG_SND_CH2_PITCH

REG_SND_CH3_PITCH

REG_SND_CH4_PITCH

Port: 080h-081h, 082h-083h, 084h-085h, 086h-087h Access: RW Size: Word Mask: 00000*** ********

Channel frequency reload values.

REG_SND_CH1_VOL

REG_SND_CH2_VOL

REG_SND_CH3_VOL

REG_SND_CH4_VOL

Port: 088h, 089h, 08Ah, 08Bh Access: RW Size: Byte Mask: ********

Channel volumes.

4-7 Left volume 0-3 Right volume

For Voice, the whole register is the PCM value.

REG_SND_SWEEP_VALUE

Port: 08Ch Access: RW Size: Byte Mask: ********

Sweep value for channel 3 in sweep mode. Each sweep tick increments the pitch of the channel by this signed value.

REG_SND_SWEEP_TIME

Port: 08Dh Access: RW Size: Byte Mask: 000*****

Sweep timing for channel 3 in sweep mode.

REG_SND_NOISE

Port: 08Eh Access: RW Size: Byte Mask: 000*****

Noise configuration for channel 4 in noise mode. When you change the noise mode, you should also set the reset bit. See the Noise section for more information on the values for Mode.

4 Enable 3 Reset (always reads 0) 0-2 Mode

REG_SND_WAVE_BASE

Port: 08Fh Access: RW Size: Byte Mask: ********

Pointer to the wave table. Register value should be address >> 6.

REG_SND_CTRL

Port: 090h Access: RW Size: Byte Mask: ***0****

Channel enable and mode bits.

7 Channel 4 mode (0=Wave, 1=Noise) 6 Channel 3 mode (0=No Sweep, 1=Sweep) 5 Channel 2 mode (0=Wave, 1=Voice) 4 Unused 3 Channel 4 enable 2 Channel 3 enable 1 Channel 2 enable 0 Channel 1 enable

REG_SND_OUTPUT

Port: 091h Access: RW Size: Byte Mask: R000****

Output control.

7 Headphones connected (0=no, 1=yes) 3 Heaphone enable 1-2 Main speaker volume shift The value sent to the speaker PWM is shifted down this many bits. 0 Main speaker enable

REG_SND_RANDOM

Port: 092h-093h Access: R Size: Word Mask: 0RRRRRRR RRRRRRRR

The current value of the noise LFSR.

REG_SND_VOICE_CTRL

Port: 094h Access: RW Size: Byte Mask: 0000****

PCM voice stereo select.

Full volume bits will override half volume bits.

3 Left enable (half volume) 2 Left enable (full volume) 1 Right enable (half volume) 0 Right enable (full volume)

REG_SND_HYPERVOICE

Port: 095h Access: RW Size: Byte Mask: ********

Unknown. (HyperVoice working sample?)

REG_SND_9697

Port: 096h-097h Access: RW Size: Word Mask: 000000** ******** (WS) 00000000 00000000 (WSC+SC)

Unknown.

REG_SND_9899

Port: 098h-099h Access: RW Size: Word Mask: 000000** ******** (WS) 00000000 00000000 (WSC+SC)

Unknown.

REG_SND_9A

Port: 09Ah Access: RW Size: Byte Mask: 00000111 (WS) 00000000 (WSC+SC)

Unknown.

REG_SND_9B

Port: 09Bh Access: RW Size: Byte Mask: 11111110 (WS) 00000000 (WSC+SC)

Unknown.

REG_SND_9C

Port: 09Ch Access: RW Size: Byte Mask: 11111111 (WS) 00000000 (WSC+SC)

Unknown.

REG_SND_9D

Port: 09Dh Access: RW Size: Byte Mask: 11111111 (WS) 00000000 (WSC+SC)

Unknown.

REG_SND_9E

Port: 09Eh Access: RW Size: Byte Mask: 000000**

Unknown.

REG_HYPER_CTRL

Port: 06Ah Access: RW Size: Byte Mask: ********

TODO: A lot of investigation

This is related to REG_HYPER_CHAN_CTRL.

7 Enable 4-6 Unknown 2-3 Scaling mode 0 data <<3-vol 1 data <<3-vol | (-0x100 << 3-vol) 2 data <<3-vol 3 data <<3 0-1 = vol

REG_HYPER_CHAN_CTRL

Port: 06Bh Access: RW Size: Byte Mask: 0**0****

TODO: A lot of investigation

This is related to REG_HYPER_CTRL.

6 Right channel enable 5 Left channel enable 0-3 Nothing?

Keypad

The keypad is multiplexed over 4 bits, using an AND mask. To get the full keypad values, iterate through each of the mask values and combine the pad data values.

For the lowest power state, turn on all enables.

When setting the enable flags, you will want to delay about 6? cycles before reading the new state to allow the circuitry to propagate the change. (TODO: Get the actual timing required)

Fun Facts

The keypad control is actually designed for a 4x4 keypad matrix, but the WonderSwan only uses 3 sets. When looking at the specification for CAIRO, there is a direct mention that the keypad input can take up to 4x4.

Considering the bit layout of REG_KEYPAD, I believe this was true for WonderSwan as well. Additionally, looking at the patents filed, it seems there were quite a number of designs with varying numbers of buttons, so it seems not unlikely that it was designed this way in case they decided to go with something even more weird.

Ports

REG_KEYPAD

Port: 0B5h Access: RW Size: Byte Mask: 0***RRRR

Keypad multiplex control, and state.

6 Button enable 5 X keys enable 4 Y keys enable 3 B, X4, Y4 2 A, X3, Y3 1 Start, X2, Y2 0 X1, Y1

With each enable flag, the respective buttons are ORed. The button states are active high.

The button circuitry uses pull-downs for unattached lines. Some games refuse to boot if unmapped buttons are treated as pull-up.

System Controller

TODO: Other things?

Ports

REG_DISP_MODE

Port: 060h Access: RW Size: Byte Mask: ***0*0**

Display mode. I think this belongs here instead of Display for various reasons.

7 BPP (0=2BPP, 1=4BPP) 6 Color? (0=Monochrome, 1=Color) (TODO: this isn't right...) 5 Format (0=Planar, 1=Packed) 0,1,3 Nothing?

These flags also change the WonderSwan to Color mode, used for things such as EEPROM size. They also affect the placement of the tiles in memory.

Feature bit5 bit6 bit7 64KB RAM NG NG OK Expanded Regs NG NG OK DMA Engine NG NG OK 1-cycle SRAM OK OK OK HyperVoice NG NG OK 16Kbit IEEP ?? ?? ?? PCG @ 4000 ?? ?? ?? PCG bank bit ?? ?? ?? Color ?? OK ??

REG_WSC_SYSTEM

Port: 062h Access: RW Size: Byte Mask: 0000000* (WSC) 1000000* (SC)

On WonderSwan this register is unmapped.

Contains whether the system is a WonderSwan Color or a SwanCrystal. Also allows you to turn off the system.

7 System (0=WonderSwan Color, 1=SwanCrystal) 0 Write 1 to power off

REG_UNK_70

Port: 070h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 0D0h.

REG_UNK_71

Port: 071h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 077h.

REG_UNK_72

Port: 072h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 0F7h.

REG_UNK_73

Port: 073h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 006h.

REG_UNK_74

Port: 074h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 0E2h.

REG_UNK_75

Port: 075h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 00Ah.

REG_UNK_76

Port: 076h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 0EAh.

REG_UNK_77

Port: 077h Access: R Size: Byte Mask: RRRRRRRR

Unmapped except on SwanCrystal. Value is 0EEh.

REG_HW_FLAGS

Port: 0A0h Access: RW Size: Byte Mask: +000**0+ (WS) +000**1+ (SC or WSC) +++++*1+ (SC in WS mode)

The only real use for this register is to check for a system with color.

7 System BIST passed (locking) 4-6 Unknown on SC's WS mode 3 Cart ROM speed (0=3 cycle, 1=1 cycle) 2 External bus width (0=8bit, 1=16bit) Most carts are only wired for 16bit bus, so this will cause improper behavior at 8bit. 1 System (0=WonderSwan, 1=WonderSwan Color or greater) 0 BIOS bank out (locking) (0=BIOS mapped, 1=Cart mapped)

Interrupts

The interrupt vector table is located at 0000:0000h, each entry is 4 bytes long containing a far pointer to the handler. There are 100h entries in the vector table, but only the CPU interrupt and the hardware interrupt entries must be filled or used for interrupt handler pointers.

CPU Interrupts

These interrupt numbers are locked to the beginning of the IVT.

INT# Name Description 00h CPUINT_DIV Divide error 01h CPUINT_STEP Single-stepping interrupt 02h CPUINT_NMI Non-maskable interrupt 03h CPUINT_BREAK INT 3 instruction 04h CPUINT_INTO Overflow interrupt 05h CPUINT_BOUNDS BOUND failure 06h CPUINT_INVALID Invalid opcode 07h CPUINT_ESCAPE Escape opcode (TODO: exists on V30MZ?)

Hardware Interrupts

These interrupts are not locked down to being at the beginning of the IVT, the register REG_INT_BASE determines the base for the hardware interrupt vectors.

These are prioritized, with the highest interrupt number having priority over lower.

Edge-triggered interrupts must be acknowledged through REG_INT_ACK to allow for another interrupt to fire. Level-triggered interrupts need to be resolved or the interrupt will fire continuously, causing your program to lock up. (TODO: is this true? I don't think so)

INT# Trigger Name Description 00h Level HWINT_SER_TX Serial TX ready interrupt 01h Edge HWINT_KEY Key press interrupt 02h Level HWINT_CART Cartridge interrupt (usually RTC alarm) 03h Level HWINT_SER_RX Serial RX ready interrupt 04h Edge HWINT_LINE Line compare interrupt 05h Edge HWINT_VBLANK_TMR V-Blank timer interrupt 06h Edge HWINT_VBLANK V-Blank interrupt 07h Edge HWINT_HBLANK_TMR H-Blank timer interrupt

Ports

REG_INT_BASE

Port: 0B0h Access: RW Size: Byte Mask: *******0 (WSC + SC) *****011 (WS)

The interrupt number offset for hardware interrupts. The bottom 3 bits are ignored by the interrupt generation hardware, so can be ignored. Actual generated interrupt numbers are (REG_INT_BASE & 0F8h) | intnum.

REG_INT_ENABLE

Port: 0B2h Access: RW Size: Byte Mask: ********

Bit mask for enabling hardware interrupts. Bits used are the same as the interrupt numbers.

REG_INT_STATUS

Port: 0B4h Access: R Size: Byte Mask: RRRRRRRR

Bit mask for currently asserted hardware interrupts. Bits used are the same as the interrupt numbers.

This register is not affected by REG_INT_ENABLE.

REG_INT_ACK

Port: 0B6h Access: W Size: Byte Mask: WWWWWWWW

Acknowledge hardware interrupts. Each set bit will acknowledge the according interrupt, cleared bits have no effect.

This register is not affected by REG_INT_ENABLE.

Reading this register returns 0.

Serial Port

The WonderSwan expansion port is primarily an external serial port. The connector has only a serial IN and OUT pin, meaning there can be no hardware flow control.

The WonderSwan serial controller has a single byte input buffer, and no output buffer. Any input buffer overrun will cause the Overrun bit in REG_SER_STATUS to be set and the serial controller will stop responding until the Overrun Reset bit is set.

Using Synchronously

To open the serial communication, set the Enable bit and the Overrun Reset bit in REG_SER_STATUS.

To close the serial communication, clear the Enable bit. You most likely want to wait for Send Empty to go high first.

To send a character, wait for Send Empty to go high, then write the data byte to REG_SER_DATA.

To receive a character, wait for Data Received to go high, then read the data byte from REG_SER_DATA. If Overrun becomes set while waiting, an overrun has managed to occur, and you'll want to set Overrun Reset.

Using Asynchronously

TODO: explain using interrupts for async transfers

Ports

REG_SER_DATA

Port: 0B1h Access: RW Size: Byte Mask: ********

Serial data. Used for both TX and RX.

REG_SER_STATUS

Port: 0B3h Access: RW Size: Byte Mask: **R00RRR

Serial status and flow control.

TODO: mask

7 Serial Enable 6 Baud rate (0=9600, 1=38400) 5 Overrun Reset 2 Send Buffer Empty 1 Overrun 0 Data Received

Internal EEPROM

WonderSwan has a 1Kbit (64x16-bit) internal EEPROM used to store information about the user and some very small amounts of game save data. WonderSwan Color upgrades the EEPROM to 16Kbit (1024x16-bit), adding a few more user info fields and increasing the game save area.

The 'owner' information can be set in the IPL program.

Hardware

On WonderSwan, the internal EEPROM is a 93C46-equivalent part. On WonderSwan Color and SwanCrystal, the EEPROM is a 93C86-equivalent. On cartridges and WSC, the parts are Seiko S-29530, which appears to not support WRAL and ERAL, unless they just decided not to document them.

SK input on chip is CARTCLK (384kHz).

This register interface is just a glorified shift register, which handles EEPROM chip I/O depending on the bits in REG_IEEP_CMD.

In ASWAN mode on SPHINX, 0 bits are inserted into the address stream to preserve compatibility.

Using

TODO: How to use

ERASE resets all bits in the address to 1.

WRAL writes the given word to all addresses.

ERAL resets all bits in all addresses to 1.

ERASE and WRITE are not permitted while protected, which can be enabled and disabled with EWDS and EWEN.

Game Saves

TODO: Explain how to deal with game save data

Contents

Owner information is easiest to understand in bytes rather than words, so I am going to specify everything in bytes (addresses and sizes) instead of words.

Addr Size Description 060h 10h Name (see name encoding section) 070h 02h Birth year (BCD) 072h 01h Birth month (1 ~ 12) (BCD) 073h 01h Birth day (1 ~ 31) (BCD) 074h 01h Sex (0=?, 1=Male, 2=Female) 075h 01h Blood type (0=?, 1=A, 2=B, 3=O, 4=AB)

WSC+SC only:

Addr Size Description 080h 03h Unknown? 083h 01h Flags b7 Unknown? Causes serious boot-time corruption that is difficult to un-do. b6 LCD contrast (0=Low, 1=High) b0-1 Default volume 084h 01h Name color 00 Black 01 Red 02 Orange 03 Yellow 04 Green // TODO There are more after this but I can't figure out what they are

Name encoding

Any value not given here is treated as a space. This mapping between values and ASCII was taken from WonderWitch's decoding.

Value ASCII Description 000h 020h Space 001h-00Ah 030h-039h Numbers 00Bh-024h 041h-05Ah Upper-case characters 025h 003h Heart 026h 00Dh Eight Note 027h 02Bh Plus 028h 02Dh Minus 029h 03Fh Question mark 02Ah 02Eh Period

Ports

REG_IEEP_DATA

Port: 0BAh-0BBh Access: RW Size: Word Mask: ******** ********

Data port.

REG_IEEP_ADDR

Port: 0BCh-0BDh Access: RW Size: Word Mask: ******** ********

Address and control port.

1Kbit: 8 Start 6-7 Command (0=Extended Command, 1=WRITE, 2=READ, 3=ERASE) 0-5 Address 16Kbit: 12 Start 10-11 Command (0=Extended Command, 1=WRITE, 2=READ, 3=ERASE) 0-9 Address

Extended commands (top 2 bits of address) 0 EWDS (Write Disable) 1 WRAL (Write All) 2 ERAL (Erase All) 3 EWEN (Write Enable)

REG_IEEP_STATUS

Port: 0BEh Access: R Size: Byte Mask: 000000**

Status port.

0-1 Status code

REG_IEEP_CMD

Port: 0BEh Access: W Size: Byte Mask: 0***0000

Behavior type. Also starts the command. Setting more than one bit causes nothing to happen.

6 EWEN/EWDS/ERAL/ERASE 5 WRITE/WRAL 4 READ

EWEN/EWDS/ERAL/ERASE Output 16 bits of data from REG_IEEP_ADDR. Status = 2 WRITE/WRAL Output 16 bits from REG_IEEP_ADDR. Output 16 bits from REG_IEEP_DATA. Status = 2 NOTE: CS goes high 1 clock after going low after command (HW bug?) For power savings probably want to emit another command after this! This is only verified for cart EEP, I presume IEEP is the same way. READ Output 16 bits from REG_IEEP_ADDR. Input 16 bits to REG_IEEP_DATA. Status = 3

DMA Controller

WonderSwan Color introduced a DMA controller. This DMA controller pauses the CPU during transfers, so code may safely assume the DMA has finished as soon as it starts.

Behavior on WonderSwan

On WonderSwan, these registers are all unmapped. This holds true in WonderSwan mode on a WonderSwan Color or SwanCrystal.

Limitations

DMA transfers in words, and all registers enforce word alignment.

DMA cannot access cart SRAM in any way, due to it using an 8-bit bus.

DMA can only transfer to IRAM, there is no way to specify a destination outside of it.

Failure Behavior

DMA has a few modes of failure. For quick failure, the DMA transfer never attempts to start, and no CPU pausing occurs. For slow failure, the DMA transfer takes the same amount of time as a completed transfer, but some or all words may not have transferred.

The cases for quick failure are:

The cases for slow failure are: (TODO: all speculation!!)

Timing

DMA transfers have very low overhead. Total transfer time from start to end is 5 + 2n cycles, where n is the number of words transferred.

Ports

REG_DMA_SRC

Port: 040h-041h Access: RW Size: Word Mask: ******** *******0

DMA source address, as a linear address (low 16 bits). This is updated after each transfer.

REG_DMA_SRC_HI

Port: 042h Access: RW Size: Byte Mask: 0000****

DMA source address, as a linear address (high 4 bits). This is updated after each transfer.

REG_DMA_DST

Port: 044h-045h Access: RW Size: Word Mask: ******** *******0

DMA destination IRAM address, as a linear address. This is updated after each transfer.

REG_DMA_LEN

Port: 046h-047h Access: RW Size: Word Mask: ******** *******0

DMA transfer size in bytes. This is updated after each transfer.

REG_DMA_CTRL

Port: 048h Access: RW Size: Byte Mask: **000000

DMA transfer control.

7 Transfer (0=Stop, 1=Start) When transfer completes, this bit becomes unset. 6 Address Step (0=Increase, 1=Decrease)

Sound DMA Controller

WonderSwan Color introduced a Sound DMA controller. Sound DMA periodically transfers a single byte to a destination.

TODO: It is currently unknown whether sound DMA and regular DMA interact.

TODO: Transfer timing is unknown.

TODO: How does looping really work? Is it affected by changing SRC during a transfer?

TODO: Does a src pointing into cart SRAM work?

Behavior on WonderSwan

On WonderSwan, these registers are all unmapped. This holds true in WonderSwan mode on a WonderSwan Color or SwanCrystal.

Ports

REG_SDMA_SRC

Port: 04Ah-04Bh Access: RW Size: Word Mask: ******** ********

Sound DMA source address, as a linear address (low 16 bits). This is updated after each transfer.

REG_SDMA_SRC_HI

Port: 04Ch Access: RW Size: Byte Mask: 0000****

Sound DMA source address, as a linear address (high 4 bits). This is updated after each transfer.

REG_SDMA_LEN

Port: 04Eh-04Fh Access: RW Size: Word Mask: ******** ********

Sound DMA transfer size in bytes (low 16 bits). This is updated after each transfer.

REG_SDMA_LEN_HI

Port: 050h Access: RW Size: Byte Mask: 0000****

Sound DMA transfer size in bytes (high 4 bits). This is updated after each transfer.

REG_SDMA_CTRL

Port: 052h Access: RW Size: Byte Mask: **0*****

Sound DMA transfer control.

7 Transfer (0=Stop, 1=Start) When transfer completes, this bit becomes unset. If looping, this bit will never unset on its own. 6 Address Step (0=Increase, 1=Decrease) 4 Destination Port (0=REG_SND_CH2_VOL, 1=REG_SND_HYPERVOICE) 3 Loop 2 Nothing? 0-1 Rate 0 CLK/768 (4000kHz) 1 CLK/512 (6000kHz) ? 2 CLK/256 (12000kHz) ? 3 CLK/128 (24000kHz) ?

Timers

WonderSwan has two timers which can be used to fire raster events, drive a sound engine, or whatever else you can think of. They are both count-down timers that support a one-shot and repeating mode.

Every time the timer ticks, the value in the corresponding REG_xTMR_CTR register is compared against zero. If it is zero, nothing further happens. Otherwise, the counter is decremented and compared against zero. If the counter is now zero, an interrupt fires, and the counter is reloaded if the timer is configured to be repeating. The enable bit is not cleared by a one-shot timer firing.

The H-Blank timer ticks every time the scan reaches X=0. The V-Blank timer ticks when the scan reaches X=0 Y=144.

Ports

REG_TMR_CTRL

Port: 0A2h Access: RW Size: Byte Mask: 0000****

Timer controls.

3 V-Blank Timer mode (0=one-shot, 1=repeating) 2 V-Blank Timer enable 1 H-Blank Timer mode (0=one-shot, 1=repeating) 0 H-Blank Timer enable

REG_HTMR_FREQ

Port: 0A4h-0A5h Access: RW Size: Word Mask: ******** ********

H-Blank Timer frequency, number of H-Blanks between interrupts.

Writes here are also written to REG_HTMR_CTR.

REG_VTMR_FREQ

Port: 0A6h-0A7h Access: RW Size: Word Mask: ******** ********

V-Blank Timer frequency, number of V-Blanks between interrupts.

Writes here are also written to REG_VTMR_CTR.

REG_HTMR_CTR

Port: 0A8h-0A9h Access: R Size: Word Mask: RRRRRRRR RRRRRRRR

Current value of H-Blank Timer counter.

REG_VTMR_CTR

Port: 0AAh-0ABh Access: R Size: Word Mask: RRRRRRRR RRRRRRRR

Current value of V-Blank Timer counter.

Code Layout

WonderSwan (Color)

TODO: I really don't know what to write here...

WonderWitch software

WonderWitch software loads all contents of the DATA section into SRAM, and uses the data there rather than from the original contents. Actual program software is run in-place on the Flash ROM, using 8086 segmentation for relocation; this means your software MAY NOT assume CS. DS may safely be assumed as 1000h, and should be set to that at most times (otherwise the Freya BIOS routines may act incorrectly). SS and SP should not be modified, as the launcher will automatically setup and configure this properly. SS should never be assumed to be the same as DS.

Code should be using a CS-relative small code model, since the area of the memory map that the program is set to is only 64K, and CS may be different between executions. Data should use a small data model, since SRAM is only 64K. This memory model is typically called small.

TODO: More in-depth on info on the 'bootstrap' and the launcher procedure.

WSR Format

WSR is a format for WonderSwan music rips. It is a program format, so the rips are made by pulling out the original sound driver code and sound data, then wrapping them in a few user-made functions, and sticking an extra footer on.

WSR Footer

The extra footer goes 16 bytes before the regular footer and has the following structure:

Offset Size Description 000h 004h 'WSRF' ASCII string 004h 001h Version number (currently 000h) 005h 001h First Track Number 006h 00Ah Reserved. (zero)

WSR CPU State

When a WSR is loaded, execution begins at 0FFFF:0000h, as usual, but AX is set to the track number to play instead of being undefined.

WSR Entry Function

Setting of interrupts for handling should be done in the entry function. (? TODO: Japanese format documentation says what follows, poorly translated) Interrupt vector is the RAM on.

Unlike KSS and HES formats, do not return from the entry function after setup is complete. Return when the song is complete (if it ever ends). Otherwise it is acceptable to be in an infinite loop.

The entry point will be jumped to each time a new track is selected, and there should be no assumptions made about the current machine state. So, switching songs should reset the entire driver.

Cartridge Overview

Cartridge Metadata

WonderSwan ROMs contain a 10 byte metadata section as the last 10 bytes of the ROM image. In most cases this is accurate, but some carts have incorrect or misleading information. A list of these games is below.

Offset Size Description -01h 001h Must be zero! 000h 001h Publisher ID (see publisher list) 001h 001h System (0=WonderSwan, 1=WonderSwan Color) BIOS seems to ignore this. 002h 001h Game ID (TODO: make a list?) Corresponds to the last 2 digits of the SKU. 003h 001h Game revision 004h 001h ROM size 000h 1Mbit? (128KB) 001h 2Mbit? (256KB) 002h 4Mbit (512KB) 003h 8Mbit (1MB) 004h 16Mbit (2MB) 005h 24Mbit (3MB) 006h 32Mbit (4MB) 007h 48Mbit (6MB) 008h 64Mbit (8MB) 009h 128Mbit (16MB) 005h 001h Save size/type 000h None 001h 64Kbit SRAM (8KB) 002h 256Kbit SRAM (32KB) 003h 1Mbit SRAM (128KB) 004h 2Mbit SRAM (256KB) 005h 4Mbit SRAM (512KB) 010h 1Kbit EEPROM 020h 16Kbit EEPROM 050h 8Kbit EEPROM? 006h 001h Flags b2 ROM access speed (0=3 cycle, 1=1 cycle) b1 ROM bus width (0=16-bit, 1=8-bit) b0 Orientation (0=Horizontal, 1=Vertical) 007h 001h RTC present (0=no, 1=yes) 008h 002h 16-bit sum of all ROM words except this one This is zero for WonderWitch.

Invalid Cart Metadata

Dicing Knight. and Judgement Silversword use WonderWitch's metadata.

RUN=DIM's publisher ID and game ID are blatantly wrong.

Turntablist DJ Battle improperly swaps the system byte and publisher ID byte.

SD Gundam GGeneration Gather Beat has the publisher and game ID bytes cleared.

Improperly cleared system byte:

Publisher ID list

These codes are the currently used publisher ID codes in commercial games. The only carts to use publisher ID 000h do so improperly.

ID Code Publisher 000h Misc. (invalid) 001h BAN Bandai 002h TAT Taito 003h TMY Tomy 004h KEX Koei 005h DTE Data East 006h AAE Asmik Ace 007h MDE Media Entertainment 008h NHB Nichibutsu 00Ah CCJ Coconuts Japan 00Bh SUM Sammy 00Ch SUN Sunsoft 00Dh PAW Mebius (?) 00Eh BPR Banpresto 010h JLC Jaleco 011h MGA Imagineer 012h KNM Konami 016h KBS Kobunsha 017h BTM Bottom Up 018h KGT Kaga Tech 019h SRV Sunrise 01Ah CFT Cyber Front 01Bh MGH Mega House 01Dh BEC Interbec 01Eh NAP Nihon Application 01Fh BVL Bandai Visual 020h ATN Athena 021h KDX KID 022h HAL HAL Corporation 023h YKE Yuki Enterprise 024h OMM Omega Micott 025h LAY Layup 026h KDK Kadokawa Shoten 027h SHL Shall Luck 028h SQR Squaresoft 02Bh TMC Tom Create 02Dh NMC Namco 02Eh SES Movic (?) 02Fh HTR E3 Staff (?) 031h VGD Vanguard 032h MGT Megatron 033h WIZ Wiz 036h CAP Capcom

Cartridge Banking

Cartridges use banking to allow access to greater amounts of ROM and RAM than the address space normally provides. There are three separate ROM banks, and one SRAM bank.

TODO: Maybe explain the common use cases for each of these banks?

Ports

REG_BANK_ROM2

Port: 0C0h Access: RW Size: Byte Mask: ********

This register contains the top bits of the ROM bank used for ROM2 accesses; the bottom 4 bits of the bank are the top 4 bits of the address accessed in that range. All 8 bits hold state. On 2001 mappers, this only outputs 4 bits, but on 2003 it outputs 6.

As an example, for register value 0F4h and accessed address 056789h, the resulting ROM address would be 0456789h on a 2001 mapper, and 03456789h on a 2003 mapper.

REG_BANK_SRAM

Port: 0C1h Access: RW Size: Byte Mask: ********

This register contains the bank of SRAM accessed.

As an example, for register value 034h and accessed address 015678h, the resulting SRAM address would be 0345678h.

REG_BANK_ROM0

Port: 0C2h Access: RW Size: Byte Mask: ********

This register contains the bank for ROM0 accesses.

As an example, for register value 034h and accessed address 025678h, the resulting ROM address would be 0345678h.

REG_BANK_ROM1

Port: 0C3h Access: RW Size: Byte Mask: ********

This register contains the bank for ROM1 accesses.

As an example, for register value 034h and accessed address 035678h, the resulting ROM address would be 0345678h.

Cartridge Real-Time Clock

Some cartridges provide an RTC for various things.

Much like the EEPROM interface, this is a glorified shift register.

TODO: More explanation, command info.

Usage

For reading commands, every read out of the REG_RTC_DATA register will feed the next byte out from the shift register, so make sure to read all the relevant data for the command.

For writing commands, you must write the first byte to REG_RTC_DATA before submitting the command, as that data byte is shifted out immediately. For commands with longer data, after submitting the command, bang the rest of the bytes out over the REG_RTC_DATA port.

Commands

Reset

Code: 060h Input: None Output: None

Resets the RTC's saved values to Year 00, Month 01, Day 01, Day-of-Week 0, Hour 00, Minute 00, Second 00.

Read Status

Code: 062h Input: None Output: 1 byte

Reads the RTC's status register. Check the Status Register section for bit information.

Write Status

Code: 063h Input: 1 byte Output: None

Writes the RTC's status register. Check the Status Register section for bit information.

Read Date

Code: 064h Input: None Output: 4 bytes (?)

Reads the RTC's date information. Check the Date Registers section for bit information.

Write Date

Code: 065h Input: 4 bytes (?) Output: None

Writes the RTC's date information. Check the Date Registers section for bit information.

Read Time

Code: 066h Input: None Output: 3 bytes (?)

Reads the RTC's time information. Check the Time Registers section for bit information.

Write Time

Code: 067h Input: 3 bytes (?) Output: None

Writes the RTC's time information. Check the Time Registers section for bit information.

Read Alarm R0

Code: 068h

Write Alarm R0

Code: 069h

Read Alarm R1

Code: 06Ah

Write Alarm R1

Code: 06Bh

Status Register

7 POWER 6 24/12 5 INTAE 4 0 3 INTME 2 0 1 INTFE 0 0

Date Registers

0-7 year 8-12 month 16-21 day 24-26 day of week 32-37 hour 39 am/pm 40-46 minute 48-54 second 55 test

Time Registers

a

Ports

REG_RTC_STATUS

Port: 0CAh Access: R Size: Byte

RTC interface status.

7 Ready for command (0=Busy, 1=Ready) 0-6 Unknown

REG_RTC_CMD

Port: 0CAh Access: W Size: Byte

RTC command.

TODO: Command list

REG_RTC_DATA

Port: 0CBh Access: RW Size: Byte

RTC data port.

Cartridge EEPROM

Some cartridges provide an EEPROM for save data. It uses the same exact interface as the Internal EEPROM.

TODO: More explanation.

TODO: Copy in info from IEEP when that section is completed.

Ports

REG_EEP_DATA

Port: 0C4h-0C5h Access: RW Size: Word

Data port.

REG_EEP_ADDR

Port: 0C6h-0C7h Access: RW Size: Word

Address and control port.

REG_EEP_STATUS

Port: 0C8h Access: R Size: Byte

Status port.

REG_EEP_CMD

Port: 0C8h Access: W Size: Byte

Command port.

Cartridge General-Purpose Outputs

The mappers provide general-purpose outputs that are used in a small number of carts for things like LEDs.

You'd think these would also allow inputs and be bi-directional ports, but nope.

Ports

REG_GPO_EN

Port: 0CCh Access: RW Size: Byte Mask: ********

4-7 Unused? 3 GPO3 enable 2 GPO2 enable 1 GPO1 enable 0 GPO0 enable

REG_GPO_DATA

Port: 0CDh Access: RW Size: Byte Mask: ********

4-7 Unused? 3 GPO3 data (reads written state) 2 GPO2 data (reads written state) 1 GPO1 data (reads written state) 0 GPO0 data (reads written state)

WonderWitch Overview

WonderWitch Update Encryption

Both System and Soft images for WonderWitch are not in plain text. They are encrypted, but the encryption is very very simple.

Here's pseudo-code for encrypting a binary:

index = 0 foreach byte in buffer { if index == 0, last_byte = 0xFF // reset last byte to 0xFF on every XMODEM sector byte ^= last_byte // \_Swap these two operations to decrypt instead buf = byte // / last_byte = buf write(byte) index = (index + 1) & 0x7F }

Using this, one can decrypt the WonderWitch firmware image, then re-encrypt it. One could also encrypt some software and put it in as Soft to turn the WonderWitch into a ghetto low-space flash cart.

WonderWitch Flash ROM

WonderWitch uses a Flash ROM to hold programs and the internal 'OS' and 'BIOS' called Freya.

This flash ROM can be written from WonderSwan code, however you must not be simultaneously executing and writing code to the flash ROM. Thus, you will need to drop code into RAM and execute from there in order to write the flash ROM.

The procedure for writing the flash can be found in any datasheet for the part, but I will explain the basic flashing procedure anyways for reference.

Firstly, change the SRAM bank to the bank you wish to write to, inclusive-OR 8. You must then swap the SRAM out for the Flash by writing 001h to REG_WW_FLASH_CE. Next, set the chip to Fast Mode by writing the following sequence to the SRAM region:

Addr Byte 0AAAh 0AAh 0555h 055h 0AAAh 020h

Next, you will perform a Fast Program by writing 0A0h to any location, then the byte you are writing to the address you wish to write to. After this, you will want to wait for the flash chip to finish writing the data. This is accomplished by reading the destination address twice and comparing bit 6. If they are equal, the flashing is complete. If they are different, and bit 5 is set, the write has timed out and failed.

If you wish to write more bytes, you may perform the Fast Program step again. Otherwise, exit Fast Mode by writing 090h then 0F0h to the destination location. Now swap the Flash back to SRAM by writing 000h to REG_WW_FLASH_CE.

WonderWitch I/O Ports

REG_WW_FLASH_CE

Port: 0CEh Access: RW Size: Byte Mask: ******** (?)

Chip enable line for the flash ROM. Only bit0 is used (?).

1-7 ? 0 Chip enable (0=SRAM, 1=Flash)

WonderGate Overview

WonderGate Terminology

Some abbreviations are used in this section, some of them well-known, some of them not.

PDC Personal Digital Cellular, the cellular standard used by supported mobile phones. PPP Point-to-Point Protocol, a fairly common protocol to connect two nodes directly.

WonderGate Interface

WonderGate works over the serial connection to the WonderSwan, so refer to the Serial Port section.

The WonderGate can communicate at both 9600 and 38400 baud, though the command sequence required for this is currently unknown. (TODO)

Connecting

Send Initialize command.

Send Get Status command. If 003h is returned, you're done and are currently connected.

Send Check PDC command to verify that the PDC is connected and working.

Send Set PPP Login command to set PPP login credentials.

Command Transfer

Sending a command to the WonderGate is merely a matter of constructing a command structure as described below, then sending it to the serial port.

Retrieving the return values consists of collecting bytes from the serial port, then interpreting them as the command structure as well. The Type and Command fields should match between the command and reply (with some exceptions).

Addr Size Description 000h 001h Type 001h 001h Zero? 002h 001h Parameter length+1 003h 001h Command 004h ... Parameters

WonderGate Commands

TODO Rewrite this a bunch

TODO Add more commands and understand them more.

Initialize

Type: 001h Command: 002h Return: Type: 001h Command: 002h 1 byte: WonderGate major version (ASCII) 1 byte: WonderGate minor version (ASCII)

Initialize WonderGate.

Close

Type: 00Fh Command: 0FFh Parameter: 4 bytes: Confirmation sequence (55,AA,55,AA) Return: Type: 00Fh Command: 0FFh 1 byte: Return value. (zero)

Close WonderGate.

Get Status

Type: 002h Command: 001h Parameter: 1 byte: 03 (why?) Return: Type: 002h Command: 002h 1 byte: Status: 002h = WonderGate is ON. 003h = PPP is in operation (phone connected to internet).

Get WonderGate status.

Check PDC

Type: 001h Command: 000h Return: Type: 001h Command: 000h 1 byte: Connection status: 000h = Connected and working. 001h = Busy. 002h = Out-of-service. 003h = Phone not connected. 1 byte: Reception level (4 bit)

Examines the attached cellular phone.

Set PPP Login

Type: 001h Command: 010h Parameter: 6 bytes: 07 00 00 00 00 01 (why?) 1 byte: User name length (or 0) ? bytes: User name (not present if no user name) 1 byte: Password length (or 0) ? bytes: Password (not present if no password) Return: Type: 001h Command: 010h 1 byte: PPP auth setting result: 1 = Success. 0 = Failure.

Set PPP authorization information.

Set DNS

Type: 001h Command: 011h Parameter: 9 bytes: 0 (why?) 4 bytes: DNS1 IP address (big endian) 4 bytes: DNS2 IP address (big endian) Return: Type: 001h Command: 011h 1 byte: DNS setting result: 1 = Success. 0 = Failure.

Set the DNS server to use.

Dial up

Type: 001h Command: 008h Parameter: 3 bytes: 00 01 03 (why?) 1 byte: Phone number length. ? bytes: Phone number to connect to. Return: Type: 001h Command: 00Bh 1 byte: Connection result: 000h = Successfully connected. 001h = No response from destination phone. 002h = Busy. 003h = Redial restricted. 0F0h = Communication disconnected. 0FFh = Mobile phone disconnected.

Connect to phone line, start PPP.

Hang up

Type: 001h Command: 00Ah Parameter: 1 byte: 01 (why?) Return: Type: 001h Command: 00Bh 1 byte: Disconnect reason.

Stop PPP, disconnect the phone line.

Get Host

Type: 011h Command: 008h Parameter: ? bytes: Name (null-terminated ASCII) Return: Type: 011h Command: 008h 1 byte: Lookup status: 1 = Success. 0 = Failure. ? bytes: Official name of the host (null-terminated ASCII) 4 bytes: IP address (big endian)

Get official host name and IP address.

New Socket

Type: 011h Command: 001h Parameter: 1 bytes: 00 (why?) Return: Type: 011h Command: 001h 1 byte: Result: -1 = Failure. else, Socket number.

Create a new TCP socket.

Connect to a Socket

Type: 011h Command: 003h Parameter: 1 bytes: Socket number 2 bytes: Address family (big endian) <=14 bytes: sa_data Return: Type: 011h Command: 003h 1 byte: ? 1 byte: Result: 1 = Success. 0 = Failure.

Connect to a socket.

Close Socket

Type: 011h Command: 007h Parameter: 1 bytes: Socket number Return: Type: 011h Command: 007h 1 byte: Result: 1 = Success. 0 = Failure.

Close a socket.

Send to Socket

Type: 011h Command: 00Eh Parameter: 1 bytes: Socket number ? bytes: Data Return: Type: 011h Command: 00Eh 1 byte: ? 1 byte: Number of bytes written

Write to a socket.

Receive from Socket

Type: 011h Command: 00Fh Parameter: 1 bytes: Socket number 1 bytes: Data length Return: Type: 011h Command: 00Fh 1 byte: ? 1 byte: Number of bytes read ? bytes: Data

Write to a socket.

CPU Overview

WonderSwan CPU is a NEC V30MZ clocked at 3.072MHz.

The CPU is binary compatible with the Intel 80186, but far higher performance. Performance characteristics:

CPU Instruction Set

This section is pretty highly unfinished.

V30MZ Registers

AX, CX, DX, BX, SI, DI, SP, BP, IP, ES, CS, SS, DS

Writing to segment registers (e.g., MOV) costs 2 extra cycles. Reading from segment registers (e.g., MOV) costs 1 extra cycle.

V30MZ Prefix Instructions

Segment Prefixes

Instruction Cycles Flags Notes ES: 1 ------ -- CS: 1 ------ -- SS: 1 ------ -- DS: 1 ------ --

These prefixes will override implicit segments with the given segment.

Repeat Prefixes

Instruction Cycles Flags Notes REPNZ 1 ------? -- REPZ 1 ------? -- REP 1 ------? Same opcode as REPZ

These prefixes will make string instructions loop. On each instruction's ending, CX will be decremented. If CX is now zero, or the prefix condition (Z=1 for REPZ, Z=0 for REPNZ) is false, the loop will end. Only SCAS and CMPS instructions check the condition, the rest will loop until CX = 0.

V30MZ Transfer Instructions

Instruction Cycles Flags Notes LEA dst, ea ! ?????? Load nearptr ea into dst LDS dst, mem ! ?????? Put farptr mem into DS:dst LES dst, mem ! ?????? Put farptr mem into ES:dst MOV dst, src 1 ?????? Load src into dst PUSH src 1 ------ SP -= 2, SS:[SP] = src POP dst 1 ------ dst = SS:[SP], SP += 2 PUSHA 9 ------ PUSHs AX,CX,DX,BX,SI,DI,SP,BP (old value of SP?) POPA 8 ------ POPs AX,CX,DX,BX,SI,DI,SP,BP (ignores SP?) XCHG a, b 3 ?????? tmp = a, a = b, b = tmp XLAT ! ?????? AL = DS:[BX + AL]

V30MZ Arithmetic Instructions

Instruction Cycles Flags Notes ADC dst, src 1 ?????? dst += src + carry ADD dst, src 1 ?????? dst += src CBW ! ?????? AX = sign-extend AL CWD ! ?????? DX:AX = sign-extend AX DEC dst 1 ?????? dst -= 1 INC dst 1 ?????? dst += 1 DIV val ! ?????? Byte: AL = AX / val, AH = AX % val Word: AX = DX:AX / val, DX = DX:AX % val IDIV val ! ?????? Byte: AL = AX / val, AH = AX % val Word: AX = DX:AX / val, DX = DX:AX % val MUL val ! ?????? Byte: AX = AL * val Word: DX:AX = AX * val IMUL val ! ?????? Byte: AX = AL * val Word: DX:AX = AX * val IMUL dst, a, b ! ?????? dst = a * b NEG val ! ?????? val = -val SBB dst, src 1 ?????? dst -= src + carry SUB dst, src 1 ?????? dst -= src

IDIV and IMUL differ from DIV and MUL in that they treat everything as signed instead of unsigned.

V30MZ Logical Instructions

Instruction Cycles Flags Notes AND dst, src 1 ?????? dst &= src OR dst, src 1 ?????? dst |= src XOR dst, src 1 ?????? dst ^= src NOT val 1 ?????? val = ~val

V30MZ Shift Instructions

Instruction Cycles Flags Notes SHL dst, cnt ! ?????? dst <<= cnt SHR dst, cnt ! ?????? dst >>= cnt SAL dst, cnt ! ?????? dst <<= cnt SAR dst, cnt ! ?????? (signed)dst >>= cnt ROL dst, cnt ! ?????? dst RCL cnt ROR dst, cnt ! ?????? dst RCR cnt RCL dst, cnt ! ?????? dst RCL cnt RCR dst, cnt ! ?????? dst RCR cnt

TODO: Explain

V30MZ Compare Instructions

Instruction Cycles Flags Notes CMP a, b 1 ?????? (flags only) a - b TEST a, b 1 ?????? (flags only) a & b

V30MZ Binary-coded Decimal Instructions

Instruction Cycles Flags Notes AAA 9 ?????? ASCII Adjust after Addition AAD base ! ?????? ASCII Adjust after Division (?) AAM base ! ?????? ASCII Adjust after Multiplication (?) AAS 9 ?????? ASCII Adjust after Subtraction DAA 10 ?????? Decimal Adjust after Addition DAS 10 ?????? Decimal Adjust after Subtraction

TODO: Explain

V30MZ I/O Instructions

Instruction Cycles Flags Notes IN dst, port ! ?????? dst = io_space[port] OUT src, port ! ?????? io_space[port] = dst

Actual write for OUT seems to occur 3 cycles from end.

V30MZ Interrupt Instructions

Instruction Cycles Flags Notes CLI ! ?????? IE=0 STI ! ?????? IE=1 HLT ! ?????? Wait for interrupt (low power mode) INT irqno ! ?????? Executes interrupt irqno BOUND G.w, E 13,20 ?????? Interrupt 4 if bounds fails INTO ! ?????? Interrupt 5 if overflow flag set IRET ! ?????? POP PC, POP CS, POP FLAGS (TODO ?)

V30MZ Flag Instructions

Instruction Cycles Flags Notes CLC ! ?????? Clear Carry STC ! ?????? Set Carry CLD ! ?????? Clear Direction STD ! ?????? Set Direction CMC ! ?????? TODO LAHF ! ?????? Low 8 bits of FLAGS=AH SAHF ! ?????? AH=Low 8 bits of FLAGS POPF ! ?????? POP FLAGS PUSHF ! ?????? PUSH FLAGS

V30MZ Misc. Instructions

Instruction Cycles Flags Notes LOCK ! ?????? Prefix I think? WAIT ! ?????? I forget NOP 1 ------ No Operation

V30MZ Branch Instructions

Instruction Cycles Flags Notes CALL nearptr ! ------ PUSH PC, PC=nearptr CALL farptr ! ------ PUSH CS, PUSH PC, CS:PC=farptr RET ! ------ POP PC RET count ! ------ SP += count, POP PC RETF ! ------ POP PC, POP CS RETF count ! ------ SP += count, POP PC, POP CS JMP nearptr ! ------ PC=nearptr JMP farptr ! ------ CS:PC=farptr JA off 1,4 ------ Jump if Above JAE off 1,4 ------ Jump if Above or Equal JB off 1,4 ------ Jump if Below JBE off 1,4 ------ Jump if Below or Equal JG off 1,4 ------ Jump if Greater JGE off 1,4 ------ Jump if Greater or Equal JL off 1,4 ------ Jump if Less JLE off 1,4 ------ Jump if Less or Equal JO off 1,4 ------ Jump if Overflow JNO off 1,4 ------ Jump if Not Overflow JS off 1,4 ------ Jump if Signed JNS off 1,4 ------ Jump if Not Signed JZ off 1,4 ------ Jump if Zero JNZ off 1,4 ------ Jump if Not Zero JPE off 1,4 ------ Jump if Parity Even JPO off 1,4 ------ Jump if Parity Odd ENTER a, b ! ?????? -- LEAVE ! ?????? -- LOOP off ! ?????? -- LOOPZ off ! ?????? -- LOOPNZ off ! ?????? -- JCXZ off ! ?????? --

V30MZ String Instructions

Instruction Cycles Flags Notes MOVSB ! ?????? -- MOVSW ! ?????? -- LODSB ! ?????? -- LODSW ! ?????? -- STOSB ! ?????? -- STOSW ! ?????? -- INSB ! ?????? -- INSW ! ?????? -- OUTSB ! ?????? -- OUTSW ! ?????? -- CMPSB ! ?????? -- CMPSW ! ?????? -- SCASB ! ?????? -- SCASW ! ?????? --

CPU Instruction Encoding

ModRM byte

ModRM byte always immediately follows the opcode. Any displacement bytes come directly after the ModRM. Other bytes for the instruction are after the displacement bytes.

6-7 MOD (Mode) 3-5 REG (Register) 0-2 RM (Register/Memory Type)

Byte Word Segment REG=0 AL AX ES REG=1 CL CX CS REG=2 DL DX SS REG=3 BL BX DS REG=4 AH SP ? (ES?) REG=5 CH BP ? (CS?) REG=6 DH SI ? (SS?) REG=7 BH DI ? (DS?)

MOD RM Address 00 000 [BX+SI] 001 [BX+DI] 010 [BP+SI] 011 [BP+DI] 100 [SI] 101 [DI] 110 disp16 111 [BX]

MOD RM Address 01 000 [BX+SI]+disp8 001 [BX+DI]+disp8 010 [BP+SI]+disp8 011 [BP+DI]+disp8 100 [SI]+disp8 101 [DI]+disp8 110 [BP]+disp8 111 [BX]+disp8

MOD RM Address 10 000 [BX+SI]+disp16 001 [BX+DI]+disp16 010 [BP+SI]+disp16 011 [BP+DI]+disp16 100 [SI]+disp16 101 [DI]+disp16 110 [BP]+disp16 111 [BX]+disp16

MOD RM Address 11 000 AX 001 CX 010 DX 011 BX 100 SP 101 BP 110 SI 111 DI

Opcode Map

-------------------------------------------------------------------------------------------------------------------------------------- | x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | -------------------------------------------------------------------------------------------------------------------------------------- 0x | ADD | ADD | ADD | ADD | ADD | ADD | PUSH | POP | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | ES | ES | -------------------------------------------------------------------------------------------------------------------------------------- 1x | ADC | ADC | ADC | ADC | ADC | ADC | PUSH | POP | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | SS | SS | -------------------------------------------------------------------------------------------------------------------------------------- 2x | AND | AND | AND | AND | AND | AND | ES: | DAA | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | | | -------------------------------------------------------------------------------------------------------------------------------------- 3x | XOR | XOR | XOR | XOR | XOR | XOR | SS: | AAA | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | | | -------------------------------------------------------------------------------------------------------------------------------------- 4x | INC | INC | INC | INC | INC | INC | INC | INC | | AX | CX | DX | BX | SP | BP | SI | DI | -------------------------------------------------------------------------------------------------------------------------------------- 5x | PUSH | PUSH | PUSH | PUSH | PUSH | PUSH | PUSH | PUSH | | AX | CX | DX | BX | SP | BP | SI | DI | -------------------------------------------------------------------------------------------------------------------------------------- 6x | PUSHA | POPA | BOUND | -- | -- | -- | -- | -- | | | | G.w E | | | | | | -------------------------------------------------------------------------------------------------------------------------------------- 7x | JO | JNO | JB | JNB | JZ | JNZ | JBE | JA | | J.b | J.b | J.b | J.b | J.b | J.b | J.b | J.b | -------------------------------------------------------------------------------------------------------------------------------------- 8x | GRP1 | GRP1 | GRP1 | GRP1 | TEST | TEST | XCHG | XCHG | | E.b I.b | E.w I.w | E.b I.b | E.w I.b | G.b E.b | G.w E.w | G.b E.b | G.w E.w | -------------------------------------------------------------------------------------------------------------------------------------- 9x | NOP | XCHG | XCHG | XCHG | XCHG | XCHG | XCHG | XCHG | | | CX AX | DX AX | BX AX | SP AX | BP AX | SI AX | DI AX | -------------------------------------------------------------------------------------------------------------------------------------- Ax | MOV | MOV | MOV | MOV | MOVSB | MOVSW | CMPSB | CMPSW | | AL A.w | AX A.w | A.w AL | A.w AX | | | | | -------------------------------------------------------------------------------------------------------------------------------------- Bx | MOV | MOV | MOV | MOV | MOV | MOV | MOV | MOV | | AL I.b | CL I.b | DL I.b | BL I.b | AH I.b | CH I.b | DH I.b | BH I.b | -------------------------------------------------------------------------------------------------------------------------------------- Cx | GRP2 | GRP2 | RET | RET | LES | LDS | MOV | MOV | | E.b I.b | E.w I.b | I.w | | G.w M.p | G.w M.p | E.b I.b | E.w I.w | -------------------------------------------------------------------------------------------------------------------------------------- Dx | GRP2 | GRP2 | GRP2 | GRP2 | AAM | AAD | -- | XLAT | | E.b 1 | E.w 1 | E.b CL | E.w CL | I.b | I.b | | | -------------------------------------------------------------------------------------------------------------------------------------- Ex | LOOPNZ | LOOPZ | LOOP | JCXZ | IN | IN | OUT | OUT | | J.b | J.b | J.b | J.b | AL I.b | AX I.b | I.b AL | I.b AX | -------------------------------------------------------------------------------------------------------------------------------------- Fx | LOCK | -- | REPNZ | REPZ | HLT | CMC | GRP3 | GRP3 | | | | | | | | E.b | E.w | --------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------------- | x8 | x9 | xA | xB | xC | xD | xE | xF | -------------------------------------------------------------------------------------------------------------------------------------- 0x | OR | OR | OR | OR | OR | OR | PUSH | -- | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | CS | | -------------------------------------------------------------------------------------------------------------------------------------- 1x | SBB | SBB | SBB | SBB | SBB | SBB | PUSH | POP | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | DS | DS | -------------------------------------------------------------------------------------------------------------------------------------- 2x | SUB | SUB | SUB | SUB | SUB | SUB | CS: | DAS | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | | | -------------------------------------------------------------------------------------------------------------------------------------- 3x | CMP | CMP | CMP | CMP | CMP | CMP | DS: | AAS | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | AL I.b | AX I.w | | | -------------------------------------------------------------------------------------------------------------------------------------- 4x | DEC | DEC | DEC | DEC | DEC | DEC | DEC | DEC | | AX | CX | DX | BX | SP | BP | SI | DI | -------------------------------------------------------------------------------------------------------------------------------------- 5x | POP | POP | POP | POP | POP | POP | POP | POP | | AX | CX | DX | BX | SP | BP | SI | DI | -------------------------------------------------------------------------------------------------------------------------------------- 6x | PUSH | IMUL | PUSH | IMUL | INSB | INSW | OUTSB | OUTSW | | I.w | G.w E.w I.w | I.b | G.b E.b I.b | | | | | -------------------------------------------------------------------------------------------------------------------------------------- 7x | JS | JNS | JPE | JPO | JL | JGE | JLE | JG | | J.b | J.b | J.b | J.b | J.b | J.b | J.b | J.b | -------------------------------------------------------------------------------------------------------------------------------------- 8x | MOV | MOV | MOV | MOV | MOV | LEA | MOV | POP | | E.b G.b | E.w G.w | G.b E.b | G.w E.w | E.w S.w | G.w M | S.w E.w | E.w | -------------------------------------------------------------------------------------------------------------------------------------- 9x | CBW | CWD | CALL | WAIT | PUSHF | POPF | SAHF | LAHF | | | | A.p | | | | | | -------------------------------------------------------------------------------------------------------------------------------------- Ax | TEST | TEST | STOSB | STOSW | LODSB | LODSW | SCASB | SCASW | | AL I.b | AX I.w | | | | | | | -------------------------------------------------------------------------------------------------------------------------------------- Bx | MOV | MOV | MOV | MOV | MOV | MOV | MOV | MOV | | AX I.w | CX I.w | DX I.w | BX I.w | SP I.w | BP I.w | SI I.w | DI I.w | -------------------------------------------------------------------------------------------------------------------------------------- Cx | ENTER | LEAVE | RETF | RETF | INT | INT | INTO | IRET | | I.w I.b | | I.w | | 3 | I.b | | | -------------------------------------------------------------------------------------------------------------------------------------- Dx | -- | -- | -- | -- | -- | -- | -- | -- | | | | | | | | | | -------------------------------------------------------------------------------------------------------------------------------------- Ex | CALL | JMP | JMP | JMP | IN | IN | OUT | OUT | | J.w | J.w | A.p | J.b | AL DX | AX DX | DX AL | DX AX | -------------------------------------------------------------------------------------------------------------------------------------- Fx | CLC | STC | CLI | STI | CLD | STD | GRP4 | GRP4 | | | | | | | | E.b | E.w | --------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------------- | REG=0 | REG=1 | REG=2 | REG=3 | REG=4 | REG=5 | REG=6 | REG=7 | -------------------------------------------------------------------------------------------------------------------------------------- GRP1 | ADD | OR | ADC | SBB | AND | SUB | XOR | CMP | | E V | E V | E V | E V | E V | E V | E V | E V | --------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------------- | REG=0 | REG=1 | REG=2 | REG=3 | REG=4 | REG=5 | REG=6 | REG=7 | -------------------------------------------------------------------------------------------------------------------------------------- GRP2 | ROL | ROR | RCL | RCR | SHL | SHR | -- | SAR | | E V | E V | E V | E V | E V | E V | | E V | --------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------------- | REG=0 | REG=1 | REG=2 | REG=3 | REG=4 | REG=5 | REG=6 | REG=7 | -------------------------------------------------------------------------------------------------------------------------------------- GRP3 | TEST | -- | NOT | NEG | MUL | IMUL | DIV | IDIV | | E I | | E | E | E | E | E | E | --------------------------------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------------------------------- | REG=0 | REG=1 | REG=2 | REG=3 | REG=4 | REG=5 | REG=6 | REG=7 | -------------------------------------------------------------------------------------------------------------------------------------- GRP4 | INC | DEC | CALL | CALL | JMP | JMP | PUSH | -- | | E | E | E | M.p | E | M.p | E | | --------------------------------------------------------------------------------------------------------------------------------------

Pinouts

Many documents label address with A1 as A0, and A0 as A(-1), etc. However, they do this erroneously, in my opinion. ROM accesses generally ignore A0 due to being in 16-bit mode, but if they were in 8-bit mode A0 would be used. Even then, SRAM accesses do use A0, so I see no good reason to use the A(-1) nomenclature outside of a pinout of the ROM chip itself (even then I think it's a poor idea).

WonderSwan is all running on a +3.3V Vdd, all references to Vdd are +3.3V.

ASWAN Pinout

SPHINX Pinout

There's so many pins and shit on here, so have a VHDL description and a pinout.

entity sphinx is port ( CLK: in std_logic_vector(1 downto 0); -- 12.288MHz PWRBRD10: inout std_logic; -- unknown -- sound SND_PWM: out std_logic; -- PWM sound output SND_LVL: out std_logic; -- output level (from sound button) as PWM?? -- cart bus A_BUS: out std_logic_vector(19 downto 0); D_BUS: inout std_logic_vector(15 downto 0); nOE: out std_logic; nWE: out std_logic; nIO: out std_logic; -- IO vs memory nSEL: out std_logic; -- Cart select nMBC: in std_logic; -- MBC serial link nIRQ: in std_logic; CARTCLK: out std_logic; -- 384kHz nCARTRST: out std_logic; -- extension port nHDPN_DETECT: in std_logic; HDPN_SDAT: out std_logic; HDPN_LRCK: out std_logic; -- 24kHz HDPN_BCLK: out std_logic; -- 768kHz SER_MISO: in std_logic; SER_MOSI: out std_logic; -- keypad KEY_SEL: out std_logic_vector(2 downto 0); -- btn,x,y KEY_DATA: in std_logic_vector(3 downto 0); KEY_SOUND: in std_logic; U6_11: out std_logic; -- goes to u6.11 -- unknown use -- ieeprom EEP_DO: in std_logic; EEP_DI: out std_logic; EEP_SK: out std_logic; EEP_CS: out std_logic; -- lcd LCD_UNK: inout std_logic; -- unknown LCD_14: inout std_logic; -- unknown LCD_17: inout std_logic; -- unknown LCD_16: inout std_logic; -- unknown LCD_15: inout std_logic; -- unknown LCD_10: inout std_logic; -- unknown LCD_13: inout std_logic; -- unknown LCD_12: inout std_logic; -- unknown LCD_11: inout std_logic; -- unknown LCD_18: inout std_logic; -- unknown U12_1: out std_logic; -- goes to u12.1 -- unknown use LCD_22: inout std_logic; -- unknown LCD_23: inout std_logic; -- unknown LCD_24: inout std_logic; -- unknown LCD_06: inout std_logic; -- unknown LCD_09: inout std_logic; -- unknown LCD_08: inout std_logic; -- unknown LCD_07: inout std_logic; -- unknown ); end sphinx; architecture rtl of sphinx is attribute chip_pin : string; attribute chip_pin of CLK : signal is "9,10"; -- why two pins? attribute chip_pin of PWRBRD10 : signal is "3"; -- unknown -- misc pins -- attribute chip_pin of NC : signal is "92"; -- attribute chip_pin of Vdd : signal is "1,6,8,30,43,61,74,90"; -- attribute chip_pin of GND : signal is "5,7,11,14,15,16,17,18,19,20,31,42,52,60,75,91,106,112,113,114,120"; -- attribute chip_pin of 2V0 : signal is "2,29,62,89"; -- sound attribute chip_pin of SND_PWM : signal is "12"; attribute chip_pin of SND_LVL : signal is "13"; -- cart bus attribute chip_pin of A_BUS : signal is "53,54,55,56,21,27,26,28,23,22,24,25,32,33,34,35,51,50,49,48"; attribute chip_pin of D_BUS : signal is "36,37,65,64,63,59,58,57,38,39,40,41,44,45,46,47"; attribute chip_pin of nOE : signal is "69"; attribute chip_pin of nWE : signal is "70"; attribute chip_pin of nIO : signal is "67"; attribute chip_pin of nSEL : signal is "68"; attribute chip_pin of nMBC : signal is "71"; attribute chip_pin of nIRQ : signal is "72"; attribute chip_pin of CARTCLK : signal is "73"; attribute chip_pin of nCARTRST : signal is "66"; -- extension port attribute chip_pin of nHDPN_DETECT : signal is "4"; attribute chip_pin of HDPN_SDAT : signal is "115"; attribute chip_pin of HDPN_LRCK : signal is "116"; attribute chip_pin of HDPN_BCLK : signal is "117"; attribute chip_pin of SER_MISO : signal is "118"; attribute chip_pin of SER_MOSI : signal is "119"; -- keypad attribute chip_pin of KEY_SEL : signal is "82,81,80"; attribute chip_pin of KEY_DATA : signal is "83,84,85,86"; attribute chip_pin of KEY_SOUND : signal is "87"; attribute chip_pin of U6_11 : signal is "88"; -- ieeprom attribute chip_pin of EEP_DO : signal is "76"; attribute chip_pin of EEP_DI : signal is "77"; attribute chip_pin of EEP_SK : signal is "78"; attribute chip_pin of EEP_CS : signal is "79"; -- lcd attribute chip_pin of LCD_UNK : signal is "93"; attribute chip_pin of LCD_14 : signal is "94"; attribute chip_pin of LCD_17 : signal is "95"; attribute chip_pin of LCD_16 : signal is "96"; attribute chip_pin of LCD_15 : signal is "97"; attribute chip_pin of LCD_10 : signal is "98"; attribute chip_pin of LCD_13 : signal is "99"; attribute chip_pin of LCD_12 : signal is "100"; attribute chip_pin of LCD_11 : signal is "101"; attribute chip_pin of LCD_18 : signal is "102"; attribute chip_pin of U12_1 : signal is "103"; attribute chip_pin of LCD_22 : signal is "104"; attribute chip_pin of LCD_23 : signal is "105"; attribute chip_pin of LCD_24 : signal is "107"; attribute chip_pin of LCD_06 : signal is "108"; attribute chip_pin of LCD_09 : signal is "109"; attribute chip_pin of LCD_08 : signal is "110"; attribute chip_pin of LCD_07 : signal is "111"; begin -- implementation end architecture;

1 Vdd 2 +2.0V 3 ? pwrbrd_10 4 i nHDPN_DETECT 5 GND 6 Vdd 7 GND 8 Vdd 9 i CLK(0) 10 i CLK(1) 11 GND 12 o SND_PWM 13 o SND_LVL 14 GND 15 GND 16 GND 17 GND 18 GND 19 GND 20 GND 21 o A_BUS(15) 22 o A_BUS(10) 23 o A_BUS(11) 24 o A_BUS(9) 25 o A_BUS(8) 26 o A_BUS(13) 27 o A_BUS(14) 28 o A_BUS(12) 29 +2.0V 30 Vdd 31 GND 32 o A_BUS(7) 33 o A_BUS(6) 34 o A_BUS(5) 35 o A_BUS(4) 36 io D_BUS(15) 37 io D_BUS(14) 38 io D_BUS(7) 39 io D_BUS(6) 40 io D_BUS(5) 41 io D_BUS(4) 42 GND 43 Vdd 44 io D_BUS(3) 45 io D_BUS(2) 46 io D_BUS(1) 47 io D_BUS(0) 48 o A_BUS(0) 49 o A_BUS(1) 50 o A_BUS(2) 51 o A_BUS(3) 52 GND 53 o A_BUS(19) 54 o A_BUS(18) 55 o A_BUS(17) 56 o A_BUS(16) 57 io D_BUS(8) 58 io D_BUS(9) 59 io D_BUS(10) 60 GND 61 Vdd 62 +2.0V 63 io D_BUS(11) 64 io D_BUS(12) 65 io D_BUS(13) 66 o nCARTRST 67 o nIO 68 o nSEL 69 o nOE 70 o nWE 71 i nMBC 72 i nIRQ 73 o CARTCLK 74 Vdd 75 GND 76 i EEP_DO 77 o EEP_DI 78 o EEP_SK 79 o EEP_CS 80 o KEY_SEL(2) 81 o KEY_SEL(1) 82 o KEY_SEL(0) 83 i KEY_DATA(0) 84 i KEY_DATA(1) 85 i KEY_DATA(2) 86 i KEY_DATA(3) 87 i KEY_SOUND 88 o U6.11 89 +2.0V 90 Vdd 91 GND 92 NC 93 ? LCD_UNK 94 ? LCD 14 95 ? LCD 17 96 ? LCD 16 97 ? LCD 15 98 ? LCD 10 99 ? LCD 13 100 ? LCD 12 101 ? LCD 11 102 ? LCD 18 103 o U12.1 104 ? LCD 22 105 ? LCD 23 106 GND 107 ? LCD 24 108 ? LCD 06 109 ? LCD 09 110 ? LCD 08 111 ? LCD 07 112 GND 113 GND 114 GND 115 o HDPN_SDAT 116 o HDPN_LRCK 117 o HDPN_BCLK 118 i SER_MISO 119 o SER_MOSI 120 GND

SPHINX2 Pinout

Ext. Port Pinout

Looking head-on at the connectors:

Female End Male End _________ | 4 3 2 1 | 1 2 3 4 | | ------- |5_6_7_8| 8 7 6 5

1 GND 2 SER_MOSI (Serial: WS-out Slave-in) 3 SER_MISO (Serial: WS-in Slave-out) 4 Vdd 5 HDPN_BCLK (768kHz clock) 6 HDPN_LRCK (24kHz clock) 7 HDPN_SDAT (sound serial) 8 /HDPN_DETECT (low for headphones connected)

Cart Connector Pinout

Looking at cart, 1 on left, 48 on right:

1 GND 2 A15 3 A10 4 A11 5 A9 6 A8 7 A13 8 A14 9 A12 10 A7 11 A6 12 A5 13 A4 14 D15 15 D14 16 D7 17 D6 18 D5 19 D4 20 D3 21 D2 22 D1 23 D0 24 Vdd 25 Vdd 26 A0 27 A1 28 A2 29 A3 30 A19 31 A18 32 A17 33 A16 34 D8 35 D9 36 D10 37 D11 38 D12 39 D13 40 /RESET 41 /IO 42 /SEL 43 /OE 44 /WE 45 /MBC 46 /CARTINT 47 CLK, 384kHz 48 GND

Cart Mapper Pinout

Cart Power Controller Pinout

IC labeled GIZA.

----- 1 --| |-- 8 2 --| _ |-- 7 3 --| / \|-- 6 4 --| \_/|-- 5 ----- 1 NC? 2 NC? 3 NC? 4 Flash.37 5 R1.B 6 SRAM.CE2 & SRAM.Vdd (need to probe more, looks like it connects to the battery) 7 GND 8 SRAM./CE1

This isn't completely mapped out yet.

Patents

There are a number of patents on various elements of the WonderSwan design.

CAIRO

Koto Labs briefly marketed an SoC called CAIRO that is a successor to the ASWAN SoC used in the WonderSwan. It is incredibly similar, with the biggest difference being the doubled clock speed.

I've not had access to any device using CAIRO, but if I can get my hands on one I'd love to poke on it.

The official specification page is archived here: http://web.archive.org/web/20071023111112/http://www.koto.co.jp/products/mono_sp.html

About This Document

WSMan written 2014-2016 by Alex Marshall (trap15), hardware documentation and programming information for the Bandai WonderSwan series.

Updates

This document will receive updates whenever errors or missing information is found. Regular updates are not to be expected.

Homepage

Feedback

If you find any information contained in this document to be incorrect, incomplete, and/or misleading, please send me an email at trap15#raidenii.net.

Any known missing/incorrect/incomplete information is generally marked with TODO or question mark(s).

Credits

Huge thanks to Martin Korth (nocash) for the general formatting and inspiration for this document.

Thanks for information and fixes,

Thanks for hardware,

General thanks to,

Changelog

rev.7

Release: 17 August 2016, 02:18:30 UTC

rev.6

Release: 19 February 2016, 02:42:45 UTC

rev.5

Release: 29 January 2016, 00:16:30 UTC

rev.4

Release: 4 September 2015, 03:32:30 UTC

rev.3

Release: 26 August 2015, 09:15:00 UTC

rev.2

Release: 17 August 2015, 09:12:45 UTC

rev.1

Release: 26 July 2014, 20:31:39 UTC

TODO

Full TODO:

Partial TODO: