summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine/wswan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/machine/wswan.c')
-rw-r--r--src/mess/machine/wswan.c1518
1 files changed, 1518 insertions, 0 deletions
diff --git a/src/mess/machine/wswan.c b/src/mess/machine/wswan.c
new file mode 100644
index 00000000000..23608e2b528
--- /dev/null
+++ b/src/mess/machine/wswan.c
@@ -0,0 +1,1518 @@
+/***************************************************************************
+
+ wswan.c
+
+ Machine file to handle emulation of the Bandai WonderSwan.
+
+ Anthony Kruize
+ Wilbert Pol
+
+TODO:
+ SRAM sizes should be in kbit instead of kbytes(?). This raises a few
+ interesting issues:
+ - mirror of smaller <64KBYTE/512kbit sram sizes
+ - banking when using 1M or 2M sram sizes
+
+***************************************************************************/
+
+#include "includes/wswan.h"
+
+#define INTERNAL_EEPROM_SIZE 1024
+
+enum enum_system { TYPE_WSWAN=0, TYPE_WSC };
+enum enum_sram { SRAM_NONE=0, SRAM_64K, SRAM_256K, SRAM_512K, SRAM_1M, SRAM_2M, EEPROM_1K, EEPROM_16K, EEPROM_8K, SRAM_UNKNOWN };
+static const char *const wswan_sram_str[] = { "none", "64Kbit SRAM", "256Kbit SRAM", "512Kbit SRAM", "1Mbit SRAM", "2Mbit SRAM", "1Kbit EEPROM", "16Kbit EEPROM", "8Kbit EEPROM", "Unknown" };
+static const int wswan_sram_size[] = { 0, 64*1024/8, 256*1024/8, 512*1024/8, 1024*1024/8, 2*1024*1024/8, 1024/8, 16*1024/8, 8*1024/8, 0 };
+
+static TIMER_CALLBACK(wswan_scanline_interrupt);
+
+
+static const UINT8 ws_portram_init[256] =
+{
+ 0x00, 0x00, 0x00/*?*/, 0xbb, 0x00, 0x00, 0x00, 0x26, 0xfe, 0xde, 0xf9, 0xfb, 0xdb, 0xd7, 0x7f, 0xf5,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9e, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x99, 0xfd, 0xb7, 0xdf,
+ 0x30, 0x57, 0x75, 0x76, 0x15, 0x73, 0x70/*77?*/, 0x77, 0x20, 0x75, 0x50, 0x36, 0x70, 0x67, 0x50, 0x77,
+ 0x57, 0x54, 0x75, 0x77, 0x75, 0x17, 0x37, 0x73, 0x50, 0x57, 0x60, 0x77, 0x70, 0x77, 0x10, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x87, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xdb, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x42, 0x00, 0x83, 0x00,
+ 0x2f, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+ 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+ 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
+ 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1
+};
+
+/*
+ Some fake bios code to initialize some registers and set up some things on the wonderswan.
+ The code from f:ffe0 which gets copied to 0:0400 is taken from a wonderswan crystal's initial
+ memory settings. Lacking real bios dumps we will use this....
+
+ The setting of SP to 2000h is what's needed to get Wonderswan Colloseum to boot.
+
+ f000:ffc0
+ FC cld
+ BC 00 20 mov sp,2000h
+ 68 00 00 push 0000h
+ 07 pop es
+ 68 00 F0 push F000h
+ 1F pop ds
+ BF 00 04 mov di,0400h
+ BE E0 FF mov si,FFE0h
+ B9 10 00 mov cx,0010h
+ F3 A4 rep movsb
+ B0 2F mov al,2Fh
+ E6 C0 out al,C0h
+ EA 00 04 00 00 jmp 0000:0400
+
+ f000:ffe0
+ E4 A0 in al, A0h
+ 0C 01 or al,01h
+ E6 A0 out al,A0h
+ EA 00 00 FF FF jmp FFFFh:0000h
+
+*/
+static const UINT8 ws_fake_bios_code[] = {
+ 0xfc, 0xbc, 0x00, 0x20, 0x68, 0x00, 0x00, 0x07, 0x68, 0x00, 0xf0, 0x1f, 0xbf, 0x00, 0x04, 0xbe,
+ 0xe0, 0xff, 0xb9, 0x10, 0x00, 0xf3, 0xa4, 0xb0, 0x2f, 0xe6, 0xc0, 0xea, 0x00, 0x04, 0x00, 0x00,
+ 0xe4, 0xa0, 0x0c, 0x01, 0xe6, 0xa0, 0xea, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0xc0, 0xff, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static void wswan_handle_irqs( running_machine &machine )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_HBLTMR ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_HBLTMR );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_VBL ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_VBL );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_VBLTMR ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_VBLTMR );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_LCMP ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_LCMP );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_SRX ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_SRX );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_RTC ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_RTC );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_KEY ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_KEY );
+ } else if ( state->m_ws_portram[0xb2] & state->m_ws_portram[0xb6] & WSWAN_IFLAG_STX ) {
+ cputag_set_input_line_and_vector( machine, "maincpu", 0, HOLD_LINE, state->m_ws_portram[0xb0] + WSWAN_INT_STX );
+ } else {
+ cputag_set_input_line(machine, "maincpu", 0, CLEAR_LINE );
+ }
+}
+
+static void wswan_set_irq_line( running_machine &machine, int irq)
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if ( state->m_ws_portram[0xb2] & irq )
+ {
+ state->m_ws_portram[0xb6] |= irq;
+ wswan_handle_irqs( machine );
+ }
+}
+
+void wswan_state::wswan_clear_irq_line(int irq)
+{
+ m_ws_portram[0xb6] &= ~irq;
+ wswan_handle_irqs( machine() );
+}
+
+static TIMER_CALLBACK(wswan_rtc_callback)
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ /* A second passed */
+ state->m_rtc.second = state->m_rtc.second + 1;
+ if ( ( state->m_rtc.second & 0x0F ) > 9 )
+ {
+ state->m_rtc.second = ( state->m_rtc.second & 0xF0 ) + 0x10;
+ }
+
+ /* Check for minute passed */
+ if ( state->m_rtc.second >= 0x60 )
+ {
+ state->m_rtc.second = 0;
+ state->m_rtc.minute = state->m_rtc.minute + 1;
+ if ( ( state->m_rtc.minute & 0x0F ) > 9 )
+ {
+ state->m_rtc.minute = ( state->m_rtc.minute & 0xF0 ) + 0x10;
+ }
+ }
+
+ /* Check for hour passed */
+ if ( state->m_rtc.minute >= 0x60 )
+ {
+ state->m_rtc.minute = 0;
+ state->m_rtc.hour = state->m_rtc.hour + 1;
+ if ( ( state->m_rtc.hour & 0x0F ) > 9 )
+ {
+ state->m_rtc.hour = ( state->m_rtc.hour & 0xF0 ) + 0x10;
+ }
+ if ( state->m_rtc.hour == 0x12 )
+ {
+ state->m_rtc.hour |= 0x80;
+ }
+ }
+
+ /* Check for day passed */
+ if ( state->m_rtc.hour >= 0x24 )
+ {
+ state->m_rtc.hour = 0;
+ state->m_rtc.day = state->m_rtc.day + 1;
+ }
+}
+
+static void wswan_machine_stop( running_machine &machine )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ device_image_interface *image = dynamic_cast<device_image_interface *>(machine.device("cart"));
+ if ( state->m_eeprom.size )
+ {
+ image->battery_save(state->m_eeprom.data, state->m_eeprom.size );
+ }
+}
+
+static void wswan_setup_bios( running_machine &machine )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if ( state->m_ws_bios_bank == NULL )
+ {
+ state->m_ws_bios_bank = auto_alloc_array(machine, UINT8, 0x10000 );
+ memcpy( state->m_ws_bios_bank + 0xffc0, ws_fake_bios_code, 0x40 );
+ }
+}
+
+MACHINE_START( wswan )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ state->m_ws_bios_bank = NULL;
+ state->m_system_type = TYPE_WSWAN;
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(wswan_machine_stop),&machine));
+ state->m_vdp.timer = machine.scheduler().timer_alloc(FUNC(wswan_scanline_interrupt), &state->m_vdp );
+ state->m_vdp.timer->adjust( attotime::from_ticks( 256, 3072000 ), 0, attotime::from_ticks( 256, 3072000 ) );
+
+ wswan_setup_bios(machine);
+
+ /* Set up RTC timer */
+ if ( state->m_rtc.present )
+ machine.scheduler().timer_pulse(attotime::from_seconds(1), FUNC(wswan_rtc_callback));
+
+ machine.device<nvram_device>("nvram")->set_base(state->m_internal_eeprom, INTERNAL_EEPROM_SIZE);
+}
+
+MACHINE_START( wscolor )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ state->m_ws_bios_bank = NULL;
+ state->m_system_type = TYPE_WSC;
+ machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(wswan_machine_stop),&machine));
+ state->m_vdp.timer = machine.scheduler().timer_alloc(FUNC(wswan_scanline_interrupt), &state->m_vdp );
+ state->m_vdp.timer->adjust( attotime::from_ticks( 256, 3072000 ), 0, attotime::from_ticks( 256, 3072000 ) );
+
+ wswan_setup_bios(machine);
+
+ /* Set up RTC timer */
+ if ( state->m_rtc.present )
+ machine.scheduler().timer_pulse(attotime::from_seconds(1), FUNC(wswan_rtc_callback));
+
+ machine.device<nvram_device>("nvram")->set_base(state->m_internal_eeprom, INTERNAL_EEPROM_SIZE);
+}
+
+MACHINE_RESET( wswan )
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ address_space *space = machine.device( "maincpu")->memory().space( AS_PROGRAM );
+
+ /* Intialize ports */
+ memcpy( state->m_ws_portram, ws_portram_init, 256 );
+
+ /* Initialize VDP */
+ memset( &state->m_vdp, 0, sizeof( state->m_vdp ) );
+
+ state->m_vdp.vram = (UINT8*)space->get_read_ptr(0);
+ state->m_vdp.palette_vram = (UINT8*)space->get_read_ptr(( state->m_system_type == TYPE_WSC ) ? 0xFE00 : 0 );
+ state->m_vdp.current_line = 145; /* Randomly chosen, beginning of VBlank period to give cart some time to boot up */
+ state->m_vdp.color_mode = 0;
+ state->m_vdp.colors_16 = 0;
+ state->m_vdp.tile_packed = 0;
+
+ render_target *target = machine.render().first_target();
+ target->set_view(state->m_rotate);
+
+ /* Initialize sound DMA */
+ memset( &state->m_sound_dma, 0, sizeof( state->m_sound_dma ) );
+
+ /* Switch in the banks */
+ state->membank( "bank2" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 1) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank3" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 1) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank4" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 12) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank5" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 11) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank6" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 10) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank7" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 9) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank8" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 8) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank9" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 7) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank10" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 6) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank11" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 5) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank12" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 4) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank13" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 3) & (state->m_ROMBanks - 1)] );
+ state->membank( "bank14" )->set_base( state->m_ROMMap[(state->m_ROMBanks - 2) & (state->m_ROMBanks - 1)] );
+ state->m_bios_disabled = 0;
+ state->membank( "bank15" )->set_base( state->m_ws_bios_bank );
+// state->membank( 15 )->set_base( state->m_ROMMap[(state->m_ROMBanks - 1) & (state->m_ROMBanks - 1)] );
+}
+
+READ8_MEMBER( wswan_state::wswan_sram_r )
+{
+ if ( m_eeprom.data == NULL )
+ {
+ return 0xFF;
+ }
+ return m_eeprom.page[ offset & ( m_eeprom.size - 1 ) ];
+}
+
+WRITE8_MEMBER( wswan_state::wswan_sram_w )
+{
+ if ( m_eeprom.data == NULL )
+ {
+ return;
+ }
+ m_eeprom.page[ offset & ( m_eeprom.size - 1 ) ] = data;
+}
+
+READ8_MEMBER( wswan_state::wswan_port_r )
+{
+ UINT8 value = m_ws_portram[offset];
+
+ if ( offset != 2 )
+ logerror( "PC=%X: port read %02X\n", cpu_get_pc( machine().device("maincpu") ), offset );
+ switch( offset )
+ {
+ case 0x02: /* Current line */
+ value = m_vdp.current_line;
+ break;
+ case 0x4A: /* Sound DMA source address (low) */
+ value = m_sound_dma.source & 0xFF;
+ break;
+ case 0x4B: /* Sound DMA source address (high) */
+ value = ( m_sound_dma.source >> 8 ) & 0xFF;
+ break;
+ case 0x4C: /* Sound DMA source memory segment */
+ value = ( m_sound_dma.source >> 16 ) & 0xFF;
+ break;
+ case 0x4E: /* Sound DMA transfer size (low) */
+ value = m_sound_dma.size & 0xFF;
+ break;
+ case 0x4F: /* Sound DMA transfer size (high) */
+ value = ( m_sound_dma.size >> 8 ) & 0xFF;
+ break;
+ case 0x52: /* Sound DMA start/stop */
+ value = m_sound_dma.enable;
+ break;
+ case 0xA0: /* Hardware type */
+ /* Bit 0 - Disable/enable Bios */
+ /* Bit 1 - Determine mono/color */
+ /* Bit 2 - Determine color/crystal */
+ value = value & ~ 0x02;
+ if ( m_system_type == TYPE_WSC )
+ {
+ value |= 2;
+ }
+ break;
+ case 0xA8:
+ value = m_vdp.timer_hblank_count & 0xFF;
+ break;
+ case 0xA9:
+ value = m_vdp.timer_hblank_count >> 8;
+ break;
+ case 0xAA:
+ value = m_vdp.timer_vblank_count & 0xFF;
+ break;
+ case 0xAB:
+ value = m_vdp.timer_vblank_count >> 8;
+ break;
+ case 0xCB: /* RTC data */
+ if ( m_ws_portram[0xca] == 0x95 && ( m_rtc.index < 7 ) )
+ {
+ switch( m_rtc.index )
+ {
+ case 0: value = m_rtc.year; break;
+ case 1: value = m_rtc.month; break;
+ case 2: value = m_rtc.day; break;
+ case 3: value = m_rtc.day_of_week; break;
+ case 4: value = m_rtc.hour; break;
+ case 5: value = m_rtc.minute; break;
+ case 6: value = m_rtc.second; break;
+ }
+ m_rtc.index++;
+ }
+ }
+
+ return value;
+}
+
+WRITE8_MEMBER( wswan_state::wswan_port_w )
+{
+ address_space *mem = m_maincpu->memory().space(AS_PROGRAM);
+ wswan_state *state = machine().driver_data<wswan_state>();
+ UINT8 input;
+ logerror( "PC=%X: port write %02X <- %02X\n", cpu_get_pc( &mem->device() ), offset, data );
+ switch( offset )
+ {
+ case 0x00: /* Display control
+ Bit 0 - Background layer enable
+ Bit 1 - Foreground layer enable
+ Bit 2 - Sprites enable
+ Bit 3 - Sprite window enable
+ Bit 4-5 - Foreground window configuration
+ 00 - Foreground layer is displayed inside and outside foreground window area
+ 01 - Unknown
+ 10 - Foreground layer is displayed only inside foreground window area
+ 11 - Foreground layer is displayed outside foreground window area
+ Bit 6-7 - Unknown
+ */
+ m_vdp.layer_bg_enable = data & 0x1;
+ m_vdp.layer_fg_enable = (data & 0x2) >> 1;
+ m_vdp.sprites_enable = (data & 0x4) >> 2;
+ m_vdp.window_sprites_enable = (data & 0x8) >> 3;
+ m_vdp.window_fg_mode = (data & 0x30) >> 4;
+ break;
+ case 0x01: /* Background colour
+ In 16 colour mode:
+ Bit 0-3 - Palette index
+ Bit 4-7 - Palette number
+ Otherwise:
+ Bit 0-2 - Main palette index
+ Bit 3-7 - Unknown
+ */
+ break;
+ case 0x02: /* Current scanline
+ Bit 0-7 - Current scanline (Most likely read-only)
+ */
+ logerror( "Write to current scanline! Current value: %d Data to write: %d\n", m_vdp.current_line, data );
+ /* Returning so we don't overwrite the value here, not that it
+ * really matters */
+ return;
+ case 0x03: /* Line compare
+ Bit 0-7 - Line compare
+ */
+ m_vdp.line_compare = data;
+ logerror( "Write to line compare: %d\n", data );
+ break;
+ case 0x04: /* Sprite table base address
+ Bit 0-5 - Determine sprite table base address 0 0xxxxxx0 00000000
+ Bit 6-7 - Unknown
+ */
+ m_vdp.sprite_table_address = ( data & 0x3F ) << 9;
+ break;
+ case 0x05: /* Number of sprite to start drawing with
+ Bit 0-7 - First sprite number
+ */
+ //m_vdp.sprite_first = data;
+ if (data) logerror("non-zero first sprite %d\n", m_vdp.sprite_first);
+ break;
+ case 0x06: /* Number of sprites to draw
+ Bit 0-7 - Number of sprites to draw
+ */
+ //m_vdp.sprite_count = data;
+ break;
+ case 0x07: /* Background/Foreground table base addresses
+ Bit 0-2 - Determine background table base address 00xxx000 00000000
+ Bit 3 - Unknown
+ Bit 4-6 - Determine foreground table base address 00xxx000 00000000
+ Bit 7 - Unknown
+ */
+ m_vdp.layer_bg_address = (data & 0x7) << 11;
+ m_vdp.layer_fg_address = (data & 0x70) << 7;
+ break;
+ case 0x08: /* Left coordinate of foreground window
+ Bit 0-7 - Left coordinate of foreground window area
+ */
+ m_vdp.window_fg_left = data;
+ break;
+ case 0x09: /* Top coordinate of foreground window
+ Bit 0-7 - Top coordinatte of foreground window area
+ */
+ m_vdp.window_fg_top = data;
+ break;
+ case 0x0A: /* Right coordinate of foreground window
+ Bit 0-7 - Right coordinate of foreground window area
+ */
+ m_vdp.window_fg_right = data;
+ break;
+ case 0x0B: /* Bottom coordinate of foreground window
+ Bit 0-7 - Bottom coordinate of foreground window area
+ */
+ m_vdp.window_fg_bottom = data;
+ break;
+ case 0x0C: /* Left coordinate of sprite window
+ Bit 0-7 - Left coordinate of sprite window area
+ */
+ m_vdp.window_sprites_left = data;
+ break;
+ case 0x0D: /* Top coordinate of sprite window
+ Bit 0-7 - Top coordinate of sprite window area
+ */
+ m_vdp.window_sprites_top = data;
+ break;
+ case 0x0E: /* Right coordinate of sprite window
+ Bit 0-7 - Right coordinate of sprite window area
+ */
+ m_vdp.window_sprites_right = data;
+ break;
+ case 0x0F: /* Bottom coordinate of sprite window
+ Bit 0-7 - Bottom coordiante of sprite window area
+ */
+ m_vdp.window_sprites_bottom = data;
+ break;
+ case 0x10: /* Background layer X scroll
+ Bit 0-7 - Background layer X scroll
+ */
+ m_vdp.layer_bg_scroll_x = data;
+ break;
+ case 0x11: /* Background layer Y scroll
+ Bit 0-7 - Background layer Y scroll
+ */
+ m_vdp.layer_bg_scroll_y = data;
+ break;
+ case 0x12: /* Foreground layer X scroll
+ Bit 0-7 - Foreground layer X scroll
+ */
+ m_vdp.layer_fg_scroll_x = data;
+ break;
+ case 0x13: /* Foreground layer Y scroll
+ Bit 0-7 - Foreground layer Y scroll
+ */
+ m_vdp.layer_fg_scroll_y = data;
+ break;
+ case 0x14: /* LCD control
+ Bit 0 - LCD enable
+ Bit 1-7 - Unknown
+ */
+ m_vdp.lcd_enable = data & 0x1;
+ break;
+ case 0x15: /* LCD icons
+ Bit 0 - LCD sleep icon enable
+ Bit 1 - Vertical position icon enable
+ Bit 2 - Horizontal position icon enable
+ Bit 3 - Dot 1 icon enable
+ Bit 4 - Dot 2 icon enable
+ Bit 5 - Dot 3 icon enable
+ Bit 6-7 - Unknown
+ */
+ m_vdp.icons = data; /* ummmmm */
+ break;
+ case 0x1c: /* Palette colors 0 and 1
+ Bit 0-3 - Gray tone setting for main palette index 0
+ Bit 4-7 - Gray tone setting for main palette index 1
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[0] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[1] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[0] = data & 0x0F;
+ m_vdp.main_palette[1] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x1d: /* Palette colors 2 and 3
+ Bit 0-3 - Gray tone setting for main palette index 2
+ Bit 4-7 - Gray tone setting for main palette index 3
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[2] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[3] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[2] = data & 0x0F;
+ m_vdp.main_palette[3] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x1e: /* Palette colors 4 and 5
+ Bit 0-3 - Gray tone setting for main palette index 4
+ Bit 4-7 - Gray tone setting for main paeltte index 5
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[4] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[5] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[4] = data & 0x0F;
+ m_vdp.main_palette[5] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x1f: /* Palette colors 6 and 7
+ Bit 0-3 - Gray tone setting for main palette index 6
+ Bit 4-7 - Gray tone setting for main palette index 7
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ int i = 15 - ( data & 0x0F );
+ int j = 15 - ( ( data & 0xF0 ) >> 4 );
+ m_vdp.main_palette[6] = ( i << 8 ) | ( i << 4 ) | i;
+ m_vdp.main_palette[7] = ( j << 8 ) | ( j << 4 ) | j;
+ }
+ else
+ {
+ m_vdp.main_palette[6] = data & 0x0F;
+ m_vdp.main_palette[7] = ( data & 0xF0 ) >> 4;
+ }
+ break;
+ case 0x20: /* tile/sprite palette settings
+ Bit 0-3 - Palette 0 index 0
+ Bit 4-7 - Palette 0 index 1 */
+ case 0x21: /* Bit 0-3 - Palette 0 index 2
+ Bit 4-7 - Palette 0 index 3 */
+ case 0x22: /* Bit 0-3 - Palette 1 index 0
+ Bit 4-7 - Palette 1 index 1 */
+ case 0x23: /* Bit 0-3 - Palette 1 index 2
+ Bit 4-7 - Palette 1 index 3 */
+ case 0x24: /* Bit 0-3 - Palette 2 index 0
+ Bit 4-7 - Palette 2 index 1 */
+ case 0x25: /* Bit 0-3 - Palette 2 index 2
+ Bit 4-7 - Palette 2 index 3 */
+ case 0x26: /* Bit 0-3 - Palette 3 index 0
+ Bit 4-7 - Palette 3 index 1 */
+ case 0x27: /* Bit 0-3 - Palette 3 index 2
+ Bit 4-7 - Palette 3 index 3 */
+ case 0x28: /* Bit 0-3 - Palette 4 index 0
+ Bit 4-7 - Palette 4 index 1 */
+ case 0x29: /* Bit 0-3 - Palette 4 index 2
+ Bit 4-7 - Palette 4 index 3 */
+ case 0x2A: /* Bit 0-3 - Palette 5 index 0
+ Bit 4-7 - Palette 5 index 1 */
+ case 0x2B: /* Bit 0-3 - Palette 5 index 2
+ Bit 4-7 - Palette 5 index 3 */
+ case 0x2C: /* Bit 0-3 - Palette 6 index 0
+ Bit 4-7 - Palette 6 index 1 */
+ case 0x2D: /* Bit 0-3 - Palette 6 index 2
+ Bit 4-7 - Palette 6 index 3 */
+ case 0x2E: /* Bit 0-3 - Palette 7 index 0
+ Bit 4-7 - Palette 7 index 1 */
+ case 0x2F: /* Bit 0-3 - Palette 7 index 2
+ Bit 4-7 - Palette 7 index 3 */
+ case 0x30: /* Bit 0-3 - Palette 8 / Sprite Palette 0 index 0
+ Bit 4-7 - Palette 8 / Sprite Palette 0 index 1 */
+ case 0x31: /* Bit 0-3 - Palette 8 / Sprite Palette 0 index 2
+ Bit 4-7 - Palette 8 / Sprite Palette 0 index 3 */
+ case 0x32: /* Bit 0-3 - Palette 9 / Sprite Palette 1 index 0
+ Bit 4-7 - Palette 9 / Sprite Palette 1 index 1 */
+ case 0x33: /* Bit 0-3 - Palette 9 / Sprite Palette 1 index 2
+ Bit 4-7 - Palette 9 / Sprite Palette 1 index 3 */
+ case 0x34: /* Bit 0-3 - Palette 10 / Sprite Palette 2 index 0
+ Bit 4-7 - Palette 10 / Sprite Palette 2 index 1 */
+ case 0x35: /* Bit 0-3 - Palette 10 / Sprite Palette 2 index 2
+ Bit 4-7 - Palette 10 / Sprite Palette 2 index 3 */
+ case 0x36: /* Bit 0-3 - Palette 11 / Sprite Palette 3 index 0
+ Bit 4-7 - Palette 11 / Sprite Palette 3 index 1 */
+ case 0x37: /* Bit 0-3 - Palette 11 / Sprite Palette 3 index 2
+ Bit 4-7 - Palette 11 / Sprite Palette 3 index 3 */
+ case 0x38: /* Bit 0-3 - Palette 12 / Sprite Palette 4 index 0
+ Bit 4-7 - Palette 12 / Sprite Palette 4 index 1 */
+ case 0x39: /* Bit 0-3 - Palette 12 / Sprite Palette 4 index 2
+ Bit 4-7 - Palette 12 / Sprite Palette 4 index 3 */
+ case 0x3A: /* Bit 0-3 - Palette 13 / Sprite Palette 5 index 0
+ Bit 4-7 - Palette 13 / Sprite Palette 5 index 1 */
+ case 0x3B: /* Bit 0-3 - Palette 13 / Sprite Palette 5 index 2
+ Bit 4-7 - Palette 13 / Sprite Palette 5 index 3 */
+ case 0x3C: /* Bit 0-3 - Palette 14 / Sprite Palette 6 index 0
+ Bit 4-7 - Palette 14 / Sprite Palette 6 index 1 */
+ case 0x3D: /* Bit 0-3 - Palette 14 / Sprite Palette 6 index 2
+ Bit 4-7 - Palette 14 / Sprite Palette 6 index 3 */
+ case 0x3E: /* Bit 0-3 - Palette 15 / Sprite Palette 7 index 0
+ Bit 4-7 - Palette 15 / Sprite Palette 7 index 1 */
+ case 0x3F: /* Bit 0-3 - Palette 15 / Sprite Palette 7 index 2
+ Bit 4-7 - Palette 15 / Sprite Palette 7 index 3 */
+ break;
+ case 0x40: /* DMA source address (low)
+ Bit 0-7 - DMA source address bit 0-7
+ */
+ case 0x41: /* DMA source address (high)
+ Bit 0-7 - DMA source address bit 8-15
+ */
+ case 0x42: /* DMA source bank
+ Bit 0-7 - DMA source bank number
+ */
+ case 0x43: /* DMA destination bank
+ Bit 0-7 - DMA destination bank number
+ */
+ case 0x44: /* DMA destination address (low)
+ Bit 0-7 - DMA destination address bit 0-7
+ */
+ case 0x45: /* DMA destination address (high)
+ Bit 0-7 - DMA destination address bit 8-15
+ */
+ case 0x46: /* Size of copied data (low)
+ Bit 0-7 - DMA size bit 0-7
+ */
+ case 0x47: /* Size of copied data (high)
+ Bit 0-7 - DMA size bit 8-15
+ */
+ break;
+ case 0x48: /* DMA control
+ Bit 0-6 - Unknown
+ Bit 7 - DMA stop/start
+ */
+ if( data & 0x80 )
+ {
+ UINT32 src, dst;
+ UINT16 length;
+
+ src = m_ws_portram[0x40] + (m_ws_portram[0x41] << 8) + (m_ws_portram[0x42] << 16);
+ dst = m_ws_portram[0x44] + (m_ws_portram[0x45] << 8) + (m_ws_portram[0x43] << 16);
+ length = m_ws_portram[0x46] + (m_ws_portram[0x47] << 8);
+ for( ; length > 0; length-- )
+ {
+ mem->write_byte(dst, mem->read_byte(src ) );
+ src++;
+ dst++;
+ }
+#ifdef DEBUG
+ logerror( "DMA src:%X dst:%X length:%d\n", src, dst, length );
+#endif
+ m_ws_portram[0x40] = src & 0xFF;
+ m_ws_portram[0x41] = ( src >> 8 ) & 0xFF;
+ m_ws_portram[0x44] = dst & 0xFF;
+ m_ws_portram[0x45] = ( dst >> 8 ) & 0xFF;
+ m_ws_portram[0x46] = length & 0xFF;
+ m_ws_portram[0x47] = ( length >> 8 ) & 0xFF;
+ data &= 0x7F;
+ }
+ break;
+ case 0x4A: /* Sound DMA source address (low)
+ Bit 0-7 - Sound DMA source address bit 0-7
+ */
+ m_sound_dma.source = ( m_sound_dma.source & 0x0FFF00 ) | data;
+ break;
+ case 0x4B: /* Sound DMA source address (high)
+ Bit 0-7 - Sound DMA source address bit 8-15
+ */
+ m_sound_dma.source = ( m_sound_dma.source & 0x0F00FF ) | ( data << 8 );
+ break;
+ case 0x4C: /* Sound DMA source memory segment
+ Bit 0-3 - Sound DMA source address segment
+ Bit 4-7 - Unknown
+ */
+ m_sound_dma.source = ( m_sound_dma.source & 0xFFFF ) | ( ( data & 0x0F ) << 16 );
+ break;
+ case 0x4D: /* Unknown */
+ break;
+ case 0x4E: /* Sound DMA transfer size (low)
+ Bit 0-7 - Sound DMA transfer size bit 0-7
+ */
+ m_sound_dma.size = ( m_sound_dma.size & 0xFF00 ) | data;
+ break;
+ case 0x4F: /* Sound DMA transfer size (high)
+ Bit 0-7 - Sound DMA transfer size bit 8-15
+ */
+ m_sound_dma.size = ( m_sound_dma.size & 0xFF ) | ( data << 8 );
+ break;
+ case 0x50: /* Unknown */
+ case 0x51: /* Unknown */
+ break;
+ case 0x52: /* Sound DMA start/stop
+ Bit 0-6 - Unknown
+ Bit 7 - Sound DMA stop/start
+ */
+ m_sound_dma.enable = data;
+ break;
+ case 0x60: /* Video mode
+ Bit 0-4 - Unknown
+ Bit 5 - Packed mode 0 = not packed mode, 1 = packed mode
+ Bit 6 - 4/16 colour mode select: 0 = 4 colour mode, 1 = 16 colour mode
+ Bit 7 - monochrome/colour mode select: 0 = monochrome mode, 1 = colour mode
+ */
+ /*
+ * 111 - packed, 16 color, use 4000/8000, color
+ * 110 - not packed, 16 color, use 4000/8000, color
+ * 101 - packed, 4 color, use 2000, color
+ * 100 - not packed, 4 color, use 2000, color
+ * 011 - packed, 16 color, use 4000/8000, monochrome
+ * 010 - not packed, 16 color , use 4000/8000, monochrome
+ * 001 - packed, 4 color, use 2000, monochrome
+ * 000 - not packed, 4 color, use 2000, monochrome - Regular WS monochrome
+ */
+ if ( m_system_type == TYPE_WSC )
+ {
+ m_vdp.color_mode = data & 0x80;
+ m_vdp.colors_16 = data & 0x40;
+ m_vdp.tile_packed = data & 0x20;
+ }
+ break;
+ case 0x80: /* Audio 1 freq (lo)
+ Bit 0-7 - Audio channel 1 frequency bit 0-7
+ */
+ case 0x81: /* Audio 1 freq (hi)
+ Bit 0-7 - Audio channel 1 frequency bit 8-15
+ */
+ case 0x82: /* Audio 2 freq (lo)
+ Bit 0-7 - Audio channel 2 frequency bit 0-7
+ */
+ case 0x83: /* Audio 2 freq (hi)
+ Bit 0-7 - Audio channel 2 frequency bit 8-15
+ */
+ case 0x84: /* Audio 3 freq (lo)
+ Bit 0-7 - Audio channel 3 frequency bit 0-7
+ */
+ case 0x85: /* Audio 3 freq (hi)
+ Bit 0-7 - Audio channel 3 frequency bit 8-15
+ */
+ case 0x86: /* Audio 4 freq (lo)
+ Bit 0-7 - Audio channel 4 frequency bit 0-7
+ */
+ case 0x87: /* Audio 4 freq (hi)
+ Bit 0-7 - Audio channel 4 frequency bit 8-15
+ */
+ case 0x88: /* Audio 1 volume
+ Bit 0-3 - Right volume audio channel 1
+ Bit 4-7 - Left volume audio channel 1
+ */
+ case 0x89: /* Audio 2 volume
+ Bit 0-3 - Right volume audio channel 2
+ Bit 4-7 - Left volume audio channel 2
+ */
+ case 0x8A: /* Audio 3 volume
+ Bit 0-3 - Right volume audio channel 3
+ Bit 4-7 - Left volume audio channel 3
+ */
+ case 0x8B: /* Audio 4 volume
+ Bit 0-3 - Right volume audio channel 4
+ Bit 4-7 - Left volume audio channel 4
+ */
+ case 0x8C: /* Sweep step
+ Bit 0-7 - Sweep step
+ */
+ case 0x8D: /* Sweep time
+ Bit 0-7 - Sweep time
+ */
+ case 0x8E: /* Noise control
+ Bit 0-2 - Noise generator type
+ Bit 3 - Reset
+ Bit 4 - Enable
+ Bit 5-7 - Unknown
+ */
+ case 0x8F: /* Sample location
+ Bit 0-7 - Sample address location 0 00xxxxxx xx000000
+ */
+ case 0x90: /* Audio control
+ Bit 0 - Audio 1 enable
+ Bit 1 - Audio 2 enable
+ Bit 2 - Audio 3 enable
+ Bit 3 - Audio 4 enable
+ Bit 4 - Unknown
+ Bit 5 - Audio 2 voice mode enable
+ Bit 6 - Audio 3 sweep mode enable
+ Bit 7 - Audio 4 noise mode enable
+ */
+ case 0x91: /* Audio output
+ Bit 0 - Mono select
+ Bit 1-2 - Output volume
+ Bit 3 - External stereo
+ Bit 4-6 - Unknown
+ Bit 7 - External speaker (Read-only, set by hardware)
+ */
+ case 0x92: /* Noise counter shift register (lo)
+ Bit 0-7 - Noise counter shift register bit 0-7
+ */
+ case 0x93: /* Noise counter shift register (hi)
+ Bit 0-6 - Noise counter shift register bit 8-14
+ bit 7 - Unknown
+ */
+ case 0x94: /* Master volume
+ Bit 0-3 - Master volume
+ Bit 4-7 - Unknown
+ */
+ wswan_sound_port_w( machine().device("custom"), offset, data );
+ break;
+ case 0xa0: /* Hardware type - this is probably read only
+ Bit 0 - Enable cartridge slot and/or disable bios
+ Bit 1 - Hardware type: 0 = WS, 1 = WSC
+ Bit 2-7 - Unknown
+ */
+ if ( ( data & 0x01 ) && !m_bios_disabled )
+ {
+ m_bios_disabled = 1;
+ membank( "bank15" )->set_base( m_ROMMap[ ( ( ( m_ws_portram[0xc0] & 0x0F ) << 4 ) | 15 ) & ( m_ROMBanks - 1 ) ] );
+ }
+ break;
+ case 0xa2: /* Timer control
+ Bit 0 - HBlank Timer enable
+ Bit 1 - HBlank Timer mode: 0 = one shot, 1 = auto reset
+ Bit 2 - VBlank Timer(1/75s) enable
+ Bit 3 - VBlank Timer mode: 0 = one shot, 1 = auto reset
+ Bit 4-7 - Unknown
+ */
+ m_vdp.timer_hblank_enable = data & 0x1;
+ m_vdp.timer_hblank_mode = (data & 0x2) >> 1;
+ m_vdp.timer_vblank_enable = (data & 0x4) >> 2;
+ m_vdp.timer_vblank_mode = (data & 0x8) >> 3;
+ break;
+ case 0xa4: /* HBlank timer frequency (low) - reload value
+ Bit 0-7 - HBlank timer reload value bit 0-7
+ */
+ m_vdp.timer_hblank_reload &= 0xff00;
+ m_vdp.timer_hblank_reload += data;
+ m_vdp.timer_hblank_count = m_vdp.timer_hblank_reload;
+ break;
+ case 0xa5: /* HBlank timer frequency (high) - reload value
+ Bit 8-15 - HBlank timer reload value bit 8-15
+ */
+ m_vdp.timer_hblank_reload &= 0xff;
+ m_vdp.timer_hblank_reload += data << 8;
+ m_vdp.timer_hblank_count = m_vdp.timer_hblank_reload;
+ break;
+ case 0xa6: /* VBlank timer frequency (low) - reload value
+ Bit 0-7 - VBlank timer reload value bit 0-7
+ */
+ m_vdp.timer_vblank_reload &= 0xff00;
+ m_vdp.timer_vblank_reload += data;
+ m_vdp.timer_vblank_count = m_vdp.timer_vblank_reload;
+ break;
+ case 0xa7: /* VBlank timer frequency (high) - reload value
+ Bit 0-7 - VBlank timer reload value bit 8-15
+ */
+ m_vdp.timer_vblank_reload &= 0xff;
+ m_vdp.timer_vblank_reload += data << 8;
+ m_vdp.timer_vblank_count = m_vdp.timer_vblank_reload;
+ break;
+ case 0xa8: /* HBlank counter (low)
+ Bit 0-7 - HBlank counter bit 0-7
+ */
+ case 0xa9: /* HBlank counter (high)
+ Bit 0-7 - HBlank counter bit 8-15
+ */
+ case 0xaa: /* VBlank counter (low)
+ Bit 0-7 - VBlank counter bit 0-7
+ */
+ case 0xab: /* VBlank counter (high)
+ Bit 0-7 - VBlank counter bit 8-15
+ */
+ break;
+
+ case 0xb0: /* Interrupt base vector
+ Bit 0-7 - Interrupt base vector
+ */
+ break;
+ case 0xb1: /* Communication byte
+ Bit 0-7 - Communication byte
+ */
+ break;
+ case 0xb2: /* Interrupt enable
+ Bit 0 - Serial transmit interrupt enable
+ Bit 1 - Key press interrupt enable
+ Bit 2 - RTC alarm interrupt enable
+ Bit 3 - Serial receive interrupt enable
+ Bit 4 - Drawing line detection interrupt enable
+ Bit 5 - VBlank timer interrupt enable
+ Bit 6 - VBlank interrupt enable
+ Bit 7 - HBlank timer interrupt enable
+ */
+ break;
+ case 0xb3: /* serial communication control
+ Bit 0 - Receive complete
+ Bit 1 - Error
+ Bit 2 - Send complete
+ Bit 3-4 - Unknown
+ Bit 5 - Send data interrupt generation
+ Bit 6 - Connection speed: 0 = 9600 bps, 1 = 38400 bps
+ bit 7 - Receive data interrupt generation
+ */
+// data |= 0x02;
+ m_ws_portram[0xb1] = 0xFF;
+ if ( data & 0x80 )
+ {
+// m_ws_portram[0xb1] = 0x00;
+ data |= 0x04;
+ }
+ if (data & 0x20 )
+ {
+// data |= 0x01;
+ }
+ break;
+ case 0xb5: /* Read controls
+ Bit 0-3 - Current state of input lines (read-only)
+ Bit 4-6 - Select line of inputs to read
+ 001 - Read Y cursors
+ 010 - Read X cursors
+ 100 - Read START,A,B buttons
+ Bit 7 - Unknown
+ */
+ data = data & 0xF0;
+ switch( data )
+ {
+ case 0x10: /* Read Y cursors: Y1 - Y2 - Y3 - Y4 */
+ input = ioport("CURSY")->read();
+ if (state->m_rotate) // reorient controls if the console is rotated
+ {
+ if (input & 0x01) data |= 0x02;
+ if (input & 0x02) data |= 0x04;
+ if (input & 0x04) data |= 0x08;
+ if (input & 0x08) data |= 0x01;
+ }
+ else
+ data = data | input;
+ break;
+ case 0x20: /* Read X cursors: X1 - X2 - X3 - X4 */
+ input = ioport("CURSX")->read();
+ if (state->m_rotate) // reorient controls if the console is rotated
+ {
+ if (input & 0x01) data |= 0x02;
+ if (input & 0x02) data |= 0x04;
+ if (input & 0x04) data |= 0x08;
+ if (input & 0x08) data |= 0x01;
+ }
+ else
+ data = data | input;
+ break;
+ case 0x40: /* Read buttons: START - A - B */
+ data = data | ioport("BUTTONS")->read();
+ break;
+ }
+ break;
+ case 0xb6: /* Interrupt acknowledge
+ Bit 0 - Serial transmit interrupt acknowledge
+ Bit 1 - Key press interrupt acknowledge
+ Bit 2 - RTC alarm interrupt acknowledge
+ Bit 3 - Serial receive interrupt acknowledge
+ Bit 4 - Drawing line detection interrupt acknowledge
+ Bit 5 - VBlank timer interrupt acknowledge
+ Bit 6 - VBlank interrupt acknowledge
+ Bit 7 - HBlank timer interrupt acknowledge
+ */
+ wswan_clear_irq_line(data);
+ data = m_ws_portram[0xB6];
+ break;
+ case 0xba: /* Internal EEPROM data (low)
+ Bit 0-7 - Internal EEPROM data transfer bit 0-7
+ */
+ case 0xbb: /* Internal EEPROM data (high)
+ Bit 0-7 - Internal EEPROM data transfer bit 8-15
+ */
+ break;
+ case 0xbc: /* Internal EEPROM address (low)
+ Bit 0-7 - Internal EEPROM address bit 1-8
+ */
+ case 0xbd: /* Internal EEPROM address (high)
+ Bit 0 - Internal EEPROM address bit 9(?)
+ Bit 1-7 - Unknown
+ Only 1KByte internal EEPROM??
+ */
+ break;
+ case 0xbe: /* Internal EEPROM command
+ Bit 0 - Read complete (read only)
+ Bit 1 - Write complete (read only)
+ Bit 2-3 - Unknown
+ Bit 4 - Read
+ Bit 5 - Write
+ Bit 6 - Protect
+ Bit 7 - Initialize
+ */
+ if ( data & 0x20 )
+ {
+ UINT16 addr = ( ( ( m_ws_portram[0xbd] << 8 ) | m_ws_portram[0xbc] ) << 1 ) & 0x1FF;
+ m_internal_eeprom[ addr ] = m_ws_portram[0xba];
+ m_internal_eeprom[ addr + 1 ] = m_ws_portram[0xbb];
+ data |= 0x02;
+ }
+ else if ( data & 0x10 )
+ {
+ UINT16 addr = ( ( ( m_ws_portram[0xbd] << 8 ) | m_ws_portram[0xbc] ) << 1 ) & 0x1FF;
+ m_ws_portram[0xba] = m_internal_eeprom[ addr ];
+ m_ws_portram[0xbb] = m_internal_eeprom[ addr + 1];
+ data |= 0x01;
+ }
+ else
+ {
+ logerror( "Unsupported internal EEPROM command: %X\n", data );
+ }
+ break;
+ case 0xc0: /* ROM bank select for banks 4-15
+ Bit 0-3 - ROM bank base register for banks 4-15
+ Bit 4-7 - Unknown
+ */
+ membank( "bank4" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 4 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank5" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 5 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank6" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 6 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank7" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 7 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank8" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 8 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank9" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 9 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank10" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 10 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank11" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 11 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank12" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 12 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank13" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 13 ) & ( m_ROMBanks - 1 ) ] );
+ membank( "bank14" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 14 ) & ( m_ROMBanks - 1 ) ] );
+ if ( m_bios_disabled )
+ {
+ membank( "bank15" )->set_base( m_ROMMap[ ( ( ( data & 0x0F ) << 4 ) | 15 ) & ( m_ROMBanks - 1 ) ] );
+ }
+ break;
+ case 0xc1: /* SRAM bank select
+ Bit 0-7 - SRAM bank to select
+ */
+ if ( m_eeprom.mode == SRAM_64K || m_eeprom.mode == SRAM_256K || m_eeprom.mode == SRAM_512K || m_eeprom.mode == SRAM_1M || m_eeprom.mode == SRAM_2M )
+ {
+ m_eeprom.page = &m_eeprom.data[ ( data * 64 * 1024 ) & ( m_eeprom.size - 1 ) ];
+ }
+ break;
+ case 0xc2: /* ROM bank select for segment 2 (0x20000 - 0x2ffff)
+ Bit 0-7 - ROM bank for segment 2
+ */
+ membank( "bank2" )->set_base( m_ROMMap[ data & ( m_ROMBanks - 1 ) ]);
+ break;
+ case 0xc3: /* ROM bank select for segment 3 (0x30000-0x3ffff)
+ Bit 0-7 - ROM bank for segment 3
+ */
+ membank( "bank3" )->set_base( m_ROMMap[ data & ( m_ROMBanks - 1 ) ]);
+ break;
+ case 0xc6: /* EEPROM address lower bits port/EEPROM address and command port
+ 1KBit EEPROM:
+ Bit 0-5 - EEPROM address bit 1-6
+ Bit 6-7 - Command
+ 00 - Extended command address bit 4-5:
+ 00 - Write disable
+ 01 - Write all
+ 10 - Erase all
+ 11 - Write enable
+ 01 - Write
+ 10 - Read
+ 11 - Erase
+ 16KBit EEPROM:
+ Bit 0-7 - EEPROM address bit 1-8
+ */
+ switch( m_eeprom.mode )
+ {
+ case EEPROM_1K:
+ m_eeprom.address = data & 0x3F;
+ m_eeprom.command = data >> 4;
+ if ( ( m_eeprom.command & 0x0C ) != 0x00 )
+ {
+ m_eeprom.command = m_eeprom.command & 0x0C;
+ }
+ break;
+ case EEPROM_16K:
+ m_eeprom.address = ( m_eeprom.address & 0xFF00 ) | data;
+ break;
+ default:
+ logerror( "Write EEPROM address/register register C6 for unsupported EEPROM type\n" );
+ break;
+ }
+ break;
+ case 0xc7: /* EEPROM higher bits/command bits port
+ 1KBit EEPROM:
+ Bit 0 - Start
+ Bit 1-7 - Unknown
+ 16KBit EEPROM:
+ Bit 0-1 - EEPROM address bit 9-10
+ Bit 2-3 - Command
+ 00 - Extended command address bit 0-1:
+ 00 - Write disable
+ 01 - Write all
+ 10 - Erase all
+ 11 - Write enable
+ 01 - Write
+ 10 - Read
+ 11 - Erase
+ Bit 4 - Start
+ Bit 5-7 - Unknown
+ */
+ switch( m_eeprom.mode )
+ {
+ case EEPROM_1K:
+ m_eeprom.start = data & 0x01;
+ break;
+ case EEPROM_16K:
+ m_eeprom.address = ( ( data & 0x03 ) << 8 ) | ( m_eeprom.address & 0xFF );
+ m_eeprom.command = data & 0x0F;
+ if ( ( m_eeprom.command & 0x0C ) != 0x00 )
+ {
+ m_eeprom.command = m_eeprom.command & 0x0C;
+ }
+ m_eeprom.start = ( data >> 4 ) & 0x01;
+ break;
+ default:
+ logerror( "Write EEPROM address/command register C7 for unsupported EEPROM type\n" );
+ break;
+ }
+ break;
+ case 0xc8: /* EEPROM command
+ Bit 0 - Read complete (read only)
+ Bit 1 - Write complete (read only)
+ Bit 2-3 - Unknown
+ Bit 4 - Read
+ Bit 5 - Write
+ Bit 6 - Protect
+ Bit 7 - Initialize
+ */
+ if ( m_eeprom.mode == EEPROM_1K || m_eeprom.mode == EEPROM_16K )
+ {
+ if ( data & 0x80 )
+ { /* Initialize */
+ logerror( "Unsupported EEPROM command 'Initialize'\n" );
+ }
+ if ( data & 0x40 )
+ { /* Protect */
+ switch( m_eeprom.command )
+ {
+ case 0x00:
+ m_eeprom.write_enabled = 0;
+ data |= 0x02;
+ break;
+ case 0x03:
+ m_eeprom.write_enabled = 1;
+ data |= 0x02;
+ break;
+ default:
+ logerror( "Unsupported 'Protect' command %X\n", m_eeprom.command );
+ }
+ }
+ if ( data & 0x20 )
+ { /* Write */
+ if ( m_eeprom.write_enabled )
+ {
+ switch( m_eeprom.command )
+ {
+ case 0x04:
+ m_eeprom.data[ ( m_eeprom.address << 1 ) + 1 ] = m_ws_portram[0xc4];
+ m_eeprom.data[ m_eeprom.address << 1 ] = m_ws_portram[0xc5];
+ data |= 0x02;
+ break;
+ default:
+ logerror( "Unsupported 'Write' command %X\n", m_eeprom.command );
+ }
+ }
+ }
+ if ( data & 0x10 )
+ { /* Read */
+ m_ws_portram[0xc4] = m_eeprom.data[ ( m_eeprom.address << 1 ) + 1 ];
+ m_ws_portram[0xc5] = m_eeprom.data[ m_eeprom.address << 1 ];
+ data |= 0x01;
+ }
+ }
+ else
+ {
+ logerror( "EEPROM command for unknown EEPROM type\n" );
+ }
+ break;
+ case 0xca: /* RTC Command
+ Bit 0-4 - RTC command
+ 10000 - Reset
+ 10010 - Write timer settings (alarm)
+ 10011 - Read timer settings (alarm)
+ 10100 - Set time/date
+ 10101 - Get time/date
+ Bit 5-6 - Unknown
+ Bit 7 - Command done (read only)
+ */
+ switch( data )
+ {
+ case 0x10: /* Reset */
+ m_rtc.index = 8;
+ m_rtc.year = 0;
+ m_rtc.month = 1;
+ m_rtc.day = 1;
+ m_rtc.day_of_week = 0;
+ m_rtc.hour = 0;
+ m_rtc.minute = 0;
+ m_rtc.second = 0;
+ m_rtc.setting = 0xFF;
+ data |= 0x80;
+ break;
+ case 0x12: /* Write Timer Settings (Alarm) */
+ m_rtc.index = 8;
+ m_rtc.setting = m_ws_portram[0xcb];
+ data |= 0x80;
+ break;
+ case 0x13: /* Read Timer Settings (Alarm) */
+ m_rtc.index = 8;
+ m_ws_portram[0xcb] = m_rtc.setting;
+ data |= 0x80;
+ break;
+ case 0x14: /* Set Time/Date */
+ m_rtc.year = m_ws_portram[0xcb];
+ m_rtc.index = 1;
+ data |= 0x80;
+ break;
+ case 0x15: /* Get Time/Date */
+ m_rtc.index = 0;
+ data |= 0x80;
+ m_ws_portram[0xcb] = m_rtc.year;
+ break;
+ default:
+ logerror( "%X: Unknown RTC command (%X) requested\n", cpu_get_pc( &mem->device() ), data );
+ }
+ break;
+ case 0xcb: /* RTC Data */
+ if ( m_ws_portram[0xca] == 0x94 && m_rtc.index < 7 )
+ {
+ switch( m_rtc.index )
+ {
+ case 0: m_rtc.year = data; break;
+ case 1: m_rtc.month = data; break;
+ case 2: m_rtc.day = data; break;
+ case 3: m_rtc.day_of_week = data; break;
+ case 4: m_rtc.hour = data; break;
+ case 5: m_rtc.minute = data; break;
+ case 6: m_rtc.second = data; break;
+ }
+ m_rtc.index++;
+ }
+ break;
+ default:
+ logerror( "Write to unsupported port: %X - %X\n", offset, data );
+ break;
+ }
+
+ /* Update the port value */
+ m_ws_portram[offset] = data;
+}
+
+static const char* wswan_determine_sram( wswan_state *state, UINT8 data )
+{
+ state->m_eeprom.write_enabled = 0;
+ state->m_eeprom.mode = SRAM_UNKNOWN;
+ switch( data )
+ {
+ case 0x00: state->m_eeprom.mode = SRAM_NONE; break;
+ case 0x01: state->m_eeprom.mode = SRAM_64K; break;
+ case 0x02: state->m_eeprom.mode = SRAM_256K; break;
+ case 0x03: state->m_eeprom.mode = SRAM_1M; break;
+ case 0x04: state->m_eeprom.mode = SRAM_2M; break;
+ case 0x05: state->m_eeprom.mode = SRAM_512K; break;
+ case 0x10: state->m_eeprom.mode = EEPROM_1K; break;
+ case 0x20: state->m_eeprom.mode = EEPROM_16K; break;
+ case 0x50: state->m_eeprom.mode = EEPROM_8K; break;
+ }
+ state->m_eeprom.size = wswan_sram_size[ state->m_eeprom.mode ];
+ return wswan_sram_str[ state->m_eeprom.mode ];
+}
+
+enum enum_romsize { ROM_4M=0, ROM_8M, ROM_16M, ROM_32M, ROM_64M, ROM_128M, ROM_UNKNOWN };
+static const char *const wswan_romsize_str[] = {
+ "4Mbit", "8Mbit", "16Mbit", "32Mbit", "64Mbit", "128Mbit", "Unknown"
+};
+
+static const char* wswan_determine_romsize( UINT8 data )
+{
+ switch( data )
+ {
+ case 0x02: return wswan_romsize_str[ ROM_4M ];
+ case 0x03: return wswan_romsize_str[ ROM_8M ];
+ case 0x04: return wswan_romsize_str[ ROM_16M ];
+ case 0x06: return wswan_romsize_str[ ROM_32M ];
+ case 0x08: return wswan_romsize_str[ ROM_64M ];
+ case 0x09: return wswan_romsize_str[ ROM_128M ];
+ }
+ return wswan_romsize_str[ ROM_UNKNOWN ];
+}
+
+DEVICE_START(wswan_cart)
+{
+ wswan_state *state = device->machine().driver_data<wswan_state>();
+ /* Initialize EEPROM structure */
+ memset( &state->m_eeprom, 0, sizeof( state->m_eeprom ) );
+ state->m_eeprom.data = NULL;
+ state->m_eeprom.page = NULL;
+
+ /* Initialize RTC structure */
+ state->m_rtc.present = 0;
+ state->m_rtc.index = 0;
+ state->m_rtc.year = 0;
+ state->m_rtc.month = 0;
+ state->m_rtc.day = 0;
+ state->m_rtc.day_of_week = 0;
+ state->m_rtc.hour = 0;
+ state->m_rtc.minute = 0;
+ state->m_rtc.second = 0;
+ state->m_rtc.setting = 0xFF;
+}
+
+DEVICE_IMAGE_LOAD(wswan_cart)
+{
+ wswan_state *state = image.device().machine().driver_data<wswan_state>();
+ UINT32 ii, size;
+ const char *sram_str;
+
+ if (image.software_entry() == NULL)
+ size = image.length();
+ else
+ size = image.get_software_region_length("rom");
+
+ state->m_ws_ram = (UINT8*) image.device().machine().device("maincpu")->memory().space(AS_PROGRAM)->get_read_ptr(0);
+ memset(state->m_ws_ram, 0, 0xffff);
+ state->m_ROMBanks = size / 65536;
+
+ for (ii = 0; ii < state->m_ROMBanks; ii++)
+ {
+ if ((state->m_ROMMap[ii] = auto_alloc_array(image.device().machine(), UINT8, 0x10000)))
+ {
+ if (image.software_entry() == NULL)
+ {
+ if (image.fread( state->m_ROMMap[ii], 0x10000) != 0x10000)
+ {
+ image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Wrongly sized ROM");
+ image.message(" Wrongly sized ROM");
+ logerror("Error while reading loading rom!\n");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ else
+ memcpy(state->m_ROMMap[ii], image.get_software_region("rom") + ii * 0x10000, 0x10000);
+ }
+ else
+ {
+ image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Unable to allocate memory for ROM");
+ image.message(" Unable to allocate memory for ROM");
+ logerror("Memory allocation failed reading rom!\n");
+ return IMAGE_INIT_FAIL;
+ }
+ }
+
+ sram_str = wswan_determine_sram(state, state->m_ROMMap[state->m_ROMBanks - 1][0xfffb]);
+
+ state->m_rtc.present = state->m_ROMMap[state->m_ROMBanks - 1][0xfffd] ? 1 : 0;
+ state->m_rotate = state->m_ROMMap[state->m_ROMBanks-1][0xfffc] & 0x01;
+
+ {
+ int sum = 0;
+ /* Spit out some info */
+ logerror("ROM DETAILS\n" );
+ logerror("\tDeveloper ID: %X\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfff6]);
+ logerror("\tMinimum system: %s\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfff7] ? "WonderSwan Color" : "WonderSwan");
+ logerror("\tCart ID: %X\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfff8]);
+ logerror("\tROM size: %s\n", wswan_determine_romsize(state->m_ROMMap[state->m_ROMBanks - 1][0xfffa]));
+ logerror("\tSRAM size: %s\n", sram_str);
+ logerror("\tFeatures: %X\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfffc]);
+ logerror("\tRTC: %s\n", state->m_ROMMap[state->m_ROMBanks - 1][0xfffd] ? "yes" : "no");
+ for (ii = 0; ii < state->m_ROMBanks; ii++)
+ {
+ int count;
+ for (count = 0; count < 0x10000; count++)
+ {
+ sum += state->m_ROMMap[ii][count];
+ }
+ }
+ sum -= state->m_ROMMap[state->m_ROMBanks - 1][0xffff];
+ sum -= state->m_ROMMap[state->m_ROMBanks - 1][0xfffe];
+ sum &= 0xffff;
+ logerror("\tChecksum: %X%X (calculated: %04X)\n", state->m_ROMMap[state->m_ROMBanks - 1][0xffff], state->m_ROMMap[state->m_ROMBanks - 1][0xfffe], sum);
+ }
+
+ if (state->m_eeprom.size != 0)
+ {
+ state->m_eeprom.data = auto_alloc_array(image.device().machine(), UINT8, state->m_eeprom.size);
+ image.battery_load(state->m_eeprom.data, state->m_eeprom.size, 0x00);
+ state->m_eeprom.page = state->m_eeprom.data;
+ }
+
+ if (image.software_entry() == NULL)
+ {
+ logerror("Image Name: %s\n", image.longname());
+ logerror("Image Year: %s\n", image.year());
+ logerror("Image Manufacturer: %s\n", image.manufacturer());
+ }
+
+ /* All done */
+ return IMAGE_INIT_PASS;
+}
+
+static TIMER_CALLBACK(wswan_scanline_interrupt)
+{
+ wswan_state *state = machine.driver_data<wswan_state>();
+ if( state->m_vdp.current_line < 144 )
+ {
+ wswan_refresh_scanline(machine);
+ }
+
+ /* Decrement 12kHz (HBlank) counter */
+ if ( state->m_vdp.timer_hblank_enable && state->m_vdp.timer_hblank_reload != 0 )
+ {
+ state->m_vdp.timer_hblank_count--;
+ logerror( "timer_hblank_count: %X\n", state->m_vdp.timer_hblank_count );
+ if ( state->m_vdp.timer_hblank_count == 0 )
+ {
+ if ( state->m_vdp.timer_hblank_mode )
+ {
+ state->m_vdp.timer_hblank_count = state->m_vdp.timer_hblank_reload;
+ }
+ else
+ {
+ state->m_vdp.timer_hblank_reload = 0;
+ }
+ logerror( "trigerring hbltmr interrupt\n" );
+ wswan_set_irq_line( machine, WSWAN_IFLAG_HBLTMR );
+ }
+ }
+
+ /* Handle Sound DMA */
+ if ( ( state->m_sound_dma.enable & 0x88 ) == 0x80 )
+ {
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM );
+ /* TODO: Output sound DMA byte */
+ state->wswan_port_w( *space, 0x89, space->read_byte(state->m_sound_dma.source ) );
+ state->m_sound_dma.size--;
+ state->m_sound_dma.source = ( state->m_sound_dma.source + 1 ) & 0x0FFFFF;
+ if ( state->m_sound_dma.size == 0 )
+ {
+ state->m_sound_dma.enable &= 0x7F;
+ }
+ }
+
+// state->m_vdp.current_line = (state->m_vdp.current_line + 1) % 159;
+
+ if( state->m_vdp.current_line == 144 ) // buffer sprite table
+ {
+ memcpy(state->m_vdp.sprite_table_buffer, &state->m_vdp.vram[state->m_vdp.sprite_table_address], 512);
+ state->m_vdp.sprite_count = state->m_ws_portram[0x06];
+ state->m_vdp.sprite_first = state->m_ws_portram[0x05]; // always zero?
+ }
+
+ if( state->m_vdp.current_line == 144 )
+ {
+ wswan_set_irq_line( machine, WSWAN_IFLAG_VBL );
+ /* Decrement 75Hz (VBlank) counter */
+ if ( state->m_vdp.timer_vblank_enable && state->m_vdp.timer_vblank_reload != 0 )
+ {
+ state->m_vdp.timer_vblank_count--;
+ logerror( "timer_vblank_count: %X\n", state->m_vdp.timer_vblank_count );
+ if ( state->m_vdp.timer_vblank_count == 0 )
+ {
+ if ( state->m_vdp.timer_vblank_mode )
+ {
+ state->m_vdp.timer_vblank_count = state->m_vdp.timer_vblank_reload;
+ }
+ else
+ {
+ state->m_vdp.timer_vblank_reload = 0;
+ }
+ logerror( "triggering vbltmr interrupt\n" );
+ wswan_set_irq_line( machine, WSWAN_IFLAG_VBLTMR );
+ }
+ }
+ }
+
+// state->m_vdp.current_line = (state->m_vdp.current_line + 1) % 159;
+
+ if ( state->m_vdp.current_line == state->m_vdp.line_compare )
+ {
+ wswan_set_irq_line( machine, WSWAN_IFLAG_LCMP );
+ }
+
+ state->m_vdp.current_line = (state->m_vdp.current_line + 1) % 159;
+}
+