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.
SoC: ASWAN
Model: SW-001
PCB ID: PTE0021C / GMPI-S5
WonderSwan (WS) is the first generation of WonderSwan.
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.
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.
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.
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
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 ---
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 ---
Rohm BU9480F Headphone adapter DAC ---
Rohm 2SK3541 Headphone adapter Amplifier ---
Suntac D825256GC001 WonderGate SoC ---
Micron M29W800AT WonderGate Flash ROM ---
Cypress CY7C1021V33L-12ZC WonderGate SRAM ---
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.
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.
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.
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.
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.
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 ?? ???
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.
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)
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)
WonderSwan has a display resolution of 224x144.
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.
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.
Depending on the current video mode, as selected by REG_DISP_MODE, different sets of palette data are used.
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.
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
The tile format and placement in memory is different depending on the current video mode, selected by REG_DISP_MODE. All tiles are 8x8.
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.
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]
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]
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.
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]
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]
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.
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
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
.
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
TODO
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
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
Port: 002h
Access: R
Size: Byte
Mask: ********
Current line being displayed.
Port: 003h
Access: RW
Size: Byte
Mask: ********
Line to fire HWINT_LINE on, compared against REG_LINE_CUR.
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
.
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?
Port: 006h
Access: RW
Size: Byte
Mask: ********
The number of sprites to draw. Any value above 080h
acts as 080h
.
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
Port: 008h
Access: RW
Size: Byte
Mask: ********
Top-left X of SCR2 Window.
Port: 009h
Access: RW
Size: Byte
Mask: ********
Top-left Y of SCR2 Window.
Port: 00Ah
Access: RW
Size: Byte
Mask: ********
Bottom-right X of SCR2 Window.
Port: 00Bh
Access: RW
Size: Byte
Mask: ********
Bottom-right Y of SCR2 Window.
Port: 00Ch
Access: RW
Size: Byte
Mask: ********
Top-left X of SPR Window.
Port: 00Dh
Access: RW
Size: Byte
Mask: ********
Top-left Y of SPR Window.
Port: 00Eh
Access: RW
Size: Byte
Mask: ********
Bottom-right X of SPR Window.
Port: 00Fh
Access: RW
Size: Byte
Mask: ********
Bottom-right Y of SPR Window.
Port: 010h
Access: RW
Size: Byte
Mask: ********
SCR1 X scroll.
Port: 011h
Access: RW
Size: Byte
Mask: ********
SCR1 Y scroll.
Port: 012h
Access: RW
Size: Byte
Mask: ********
SCR2 X scroll.
Port: 013h
Access: RW
Size: Byte
Mask: ********
SCR2 Y scroll.
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
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
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.
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
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
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
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.
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 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.
TODO: Overview
On WonderSwan, these registers are unmapped. This holds true in WonderSwan mode on a WonderSwan Color or SwanCrystal.
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.
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.
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.
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.
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.
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 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 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.
Port: 080h-081h, 082h-083h, 084h-085h, 086h-087h
Access: RW
Size: Word
Mask: 00000*** ********
Channel frequency reload values.
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.
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.
Port: 08Dh
Access: RW
Size: Byte
Mask: 000*****
Sweep timing for channel 3 in sweep mode.
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
Port: 08Fh
Access: RW
Size: Byte
Mask: ********
Pointer to the wave table. Register value should be address >> 6
.
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
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
Port: 092h-093h
Access: R
Size: Word
Mask: 0RRRRRRR RRRRRRRR
The current value of the noise LFSR.
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)
Port: 095h
Access: RW
Size: Byte
Mask: ********
Unknown. (HyperVoice working sample?)
Port: 096h-097h
Access: RW
Size: Word
Mask: 000000** ******** (WS)
00000000 00000000 (WSC+SC)
Unknown.
Port: 098h-099h
Access: RW
Size: Word
Mask: 000000** ******** (WS)
00000000 00000000 (WSC+SC)
Unknown.
Port: 09Ah
Access: RW
Size: Byte
Mask: 00000111 (WS)
00000000 (WSC+SC)
Unknown.
Port: 09Bh
Access: RW
Size: Byte
Mask: 11111110 (WS)
00000000 (WSC+SC)
Unknown.
Port: 09Ch
Access: RW
Size: Byte
Mask: 11111111 (WS)
00000000 (WSC+SC)
Unknown.
Port: 09Dh
Access: RW
Size: Byte
Mask: 11111111 (WS)
00000000 (WSC+SC)
Unknown.
Port: 09Eh
Access: RW
Size: Byte
Mask: 000000**
Unknown.
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
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?
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)
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.
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.
TODO: Other things?
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 ??
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
Port: 070h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 0D0h
.
Port: 071h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 077h
.
Port: 072h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 0F7h
.
Port: 073h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 006h
.
Port: 074h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 0E2h
.
Port: 075h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 00Ah
.
Port: 076h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 0EAh
.
Port: 077h
Access: R
Size: Byte
Mask: RRRRRRRR
Unmapped except on SwanCrystal. Value is 0EEh
.
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)
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.
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?)
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
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
.
Port: 0B2h
Access: RW
Size: Byte
Mask: ********
Bit mask for enabling hardware interrupts. Bits used are the same as the interrupt numbers.
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.
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.
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.
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.
TODO: explain using interrupts for async transfers
Port: 0B1h
Access: RW
Size: Byte
Mask: ********
Serial data. Used for both TX and RX.
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
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.
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.
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.
TODO: Explain how to deal with game save data
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
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
Port: 0BAh-0BBh
Access: RW
Size: Word
Mask: ******** ********
Data port.
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)
Port: 0BEh
Access: R
Size: Byte
Mask: 000000**
Status port.
0-1 Status code
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
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.
On WonderSwan, these registers are all unmapped. This holds true in WonderSwan mode on a WonderSwan Color or SwanCrystal.
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.
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:
0
.The cases for slow failure are: (TODO: all speculation!!)
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.
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.
Port: 042h
Access: RW
Size: Byte
Mask: 0000****
DMA source address, as a linear address (high 4 bits). This is updated after each transfer.
Port: 044h-045h
Access: RW
Size: Word
Mask: ******** *******0
DMA destination IRAM address, as a linear address. This is updated after each transfer.
Port: 046h-047h
Access: RW
Size: Word
Mask: ******** *******0
DMA transfer size in bytes. This is updated after each transfer.
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)
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?
On WonderSwan, these registers are all unmapped. This holds true in WonderSwan mode on a WonderSwan Color or SwanCrystal.
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.
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.
Port: 04Eh-04Fh
Access: RW
Size: Word
Mask: ******** ********
Sound DMA transfer size in bytes (low 16 bits). This is updated after each transfer.
Port: 050h
Access: RW
Size: Byte
Mask: 0000****
Sound DMA transfer size in bytes (high 4 bits). This is updated after each transfer.
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) ?
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
.
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
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.
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.
Port: 0A8h-0A9h
Access: R
Size: Word
Mask: RRRRRRRR RRRRRRRR
Current value of H-Blank Timer counter.
Port: 0AAh-0ABh
Access: R
Size: Word
Mask: RRRRRRRR RRRRRRRR
Current value of V-Blank Timer counter.
TODO: I really don't know what to write here...
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 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.
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)
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.
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.
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.
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:
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
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?
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.
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
.
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
.
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
.
Some cartridges provide an RTC for various things.
Much like the EEPROM interface, this is a glorified shift register.
TODO: More explanation, command info.
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.
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.
Code: 062h
Input: None
Output: 1 byte
Reads the RTC's status register. Check the Status Register section for bit information.
Code: 063h
Input: 1 byte
Output: None
Writes the RTC's status register. Check the Status Register section for bit information.
Code: 064h
Input: None
Output: 4 bytes (?)
Reads the RTC's date information. Check the Date Registers section for bit information.
Code: 065h
Input: 4 bytes (?)
Output: None
Writes the RTC's date information. Check the Date Registers section for bit information.
Code: 066h
Input: None
Output: 3 bytes (?)
Reads the RTC's time information. Check the Time Registers section for bit information.
Code: 067h
Input: 3 bytes (?)
Output: None
Writes the RTC's time information. Check the Time Registers section for bit information.
Code: 068h
Code: 069h
Code: 06Ah
Code: 06Bh
7 POWER
6 24/12
5 INTAE
4 0
3 INTME
2 0
1 INTFE
0 0
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
a
Port: 0CAh
Access: R
Size: Byte
RTC interface status.
7 Ready for command (0=Busy, 1=Ready)
0-6 Unknown
Port: 0CAh
Access: W
Size: Byte
RTC command.
TODO: Command list
Port: 0CBh
Access: RW
Size: Byte
RTC data port.
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.
Port: 0C4h-0C5h
Access: RW
Size: Word
Data port.
Port: 0C6h-0C7h
Access: RW
Size: Word
Address and control port.
Port: 0C8h
Access: R
Size: Byte
Status port.
Port: 0C8h
Access: W
Size: Byte
Command port.
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.
Port: 0CCh
Access: RW
Size: Byte
Mask: ********
4-7 Unused?
3 GPO3 enable
2 GPO2 enable
1 GPO1 enable
0 GPO0 enable
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)
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 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.
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)
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 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)
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.
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
TODO Rewrite this a bunch
TODO Add more commands and understand them more.
Type: 001h
Command: 002h
Return:
Type: 001h
Command: 002h
1 byte:
WonderGate major version (ASCII)
1 byte:
WonderGate minor version (ASCII)
Initialize WonderGate.
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.
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.
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.
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.
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.
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.
Type: 001h
Command: 00Ah
Parameter:
1 byte:
01 (why?)
Return:
Type: 001h
Command: 00Bh
1 byte:
Disconnect reason.
Stop PPP, disconnect the phone line.
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.
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.
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.
Type: 011h
Command: 007h
Parameter:
1 bytes:
Socket number
Return:
Type: 011h
Command: 007h
1 byte:
Result:
1 = Success.
0 = Failure.
Close a 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.
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.
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:
This section is pretty highly unfinished.
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.
Instruction Cycles Flags Notes
ES: 1 ------ --
CS: 1 ------ --
SS: 1 ------ --
DS: 1 ------ --
These prefixes will override implicit segments with the given segment.
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.
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]
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.
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
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
Instruction Cycles Flags Notes
CMP a, b 1 ?????? (flags only) a - b
TEST a, b 1 ?????? (flags only) a & b
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
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.
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 ?)
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
Instruction Cycles Flags Notes
LOCK ! ?????? Prefix I think?
WAIT ! ?????? I forget
NOP 1 ------ No Operation
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 ! ?????? --
Instruction Cycles Flags Notes
MOVSB ! ?????? --
MOVSW ! ?????? --
LODSB ! ?????? --
LODSW ! ?????? --
STOSB ! ?????? --
STOSW ! ?????? --
INSB ! ?????? --
INSW ! ?????? --
OUTSB ! ?????? --
OUTSW ! ?????? --
CMPSB ! ?????? --
CMPSW ! ?????? --
SCASB ! ?????? --
SCASW ! ?????? --
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
--------------------------------------------------------------------------------------------------------------------------------------
| 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 | |
--------------------------------------------------------------------------------------------------------------------------------------
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.
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
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)
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
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.
There are a number of patents on various elements of the WonderSwan design.
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
WSMan written 2014-2016 by Alex Marshall (trap15), hardware documentation and programming information for the Bandai WonderSwan series.
This document will receive updates whenever errors or missing information is found. Regular updates are not to be expected.
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).
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,
Release: 17 August 2016, 02:18:30 UTC
Release: 19 February 2016, 02:42:45 UTC
Release: 29 January 2016, 00:16:30 UTC
Release: 4 September 2015, 03:32:30 UTC
Release: 26 August 2015, 09:15:00 UTC
Release: 17 August 2015, 09:12:45 UTC
Release: 26 July 2014, 20:31:39 UTC
Full TODO:
Partial TODO: