diff options
-rw-r--r-- | scripts/target/mame/mess.lua | 2 | ||||
-rw-r--r-- | src/mame/drivers/wswan.cpp | 784 | ||||
-rw-r--r-- | src/mame/includes/wswan.h | 120 | ||||
-rw-r--r-- | src/mame/machine/wswan.cpp | 664 | ||||
-rw-r--r-- | src/mame/video/wswan.cpp | 9 | ||||
-rw-r--r-- | src/mame/video/wswan.h | 23 |
6 files changed, 749 insertions, 853 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index e8f61af2fcf..6f08d0f2ba7 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -1863,10 +1863,8 @@ files { MAME_DIR .. "src/mame/drivers/rx78.cpp", MAME_DIR .. "src/mame/drivers/tamag1.cpp", MAME_DIR .. "src/mame/drivers/wswan.cpp", - MAME_DIR .. "src/mame/includes/wswan.h", MAME_DIR .. "src/mame/audio/wswan.cpp", MAME_DIR .. "src/mame/audio/wswan.h", - MAME_DIR .. "src/mame/machine/wswan.cpp", MAME_DIR .. "src/mame/video/wswan.cpp", MAME_DIR .. "src/mame/video/wswan.h", MAME_DIR .. "src/mame/drivers/bandai_design_master.cpp", diff --git a/src/mame/drivers/wswan.cpp b/src/mame/drivers/wswan.cpp index af411c7fb78..0fd49940a3c 100644 --- a/src/mame/drivers/wswan.cpp +++ b/src/mame/drivers/wswan.cpp @@ -12,85 +12,214 @@ Based on the WStech documentation by Judge and Dox. + Usage: + Keep START button pressed during startup (or reset) to enter the internal + configuration menu. + Known issues/TODOs: - - Get the V30MZ core into MAME, still need to remove some nec specific - instructions and fix the flags handling of the div/mul instructions. - Add support for noise sound - Add support for voice sound - Add support for enveloped sound - Perform video DMA at proper timing. - - Add sound DMA. - - Setup some reasonable values in the internal EEPROM area? - Add (real/proper) RTC support. - - Look into timing issues like in Puzzle Bobble. VBlank interrupt lasts very long - which causes sprites to be disabled until about 10%-40% of drawing the screen. - The real unit seems to display things fine, need a real unit + real cart to - verify. - - Is background color setting really ok? - - Get a dump of the internal BIOSes. - Swan Crystal can handle up to 512Mbit ROMs?????? - + - 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 + - The units likely came with the name "WONDERSWAN" configured in the + internal EEPOM ***************************************************************************/ #include "emu.h" -#include "includes/wswan.h" - +#include "cpu/v30mz/v30mz.h" +#include "machine/nvram.h" +#include "audio/wswan.h" +#include "video/wswan.h" +#include "bus/wswan/slot.h" +#include "bus/wswan/rom.h" +#include "emupal.h" +#include "render.h" #include "screen.h" #include "softlist.h" #include "speaker.h" #include "wswan.lh" -void wswan_state::wswan_mem(address_map &map) +class wswan_state : public driver_device +{ +public: + wswan_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_vdp(*this, "vdp"), + m_sound(*this, "custom"), + m_cart(*this, "cartslot"), + m_region_maincpu(*this, "maincpu"), + m_cursx(*this, "CURSX"), + m_cursy(*this, "CURSY"), + m_buttons(*this, "BUTTONS") + { } + + void wswan(machine_config &config); + +protected: + // Interrupt flags + static const u8 WSWAN_IFLAG_STX = 0x01; + static const u8 WSWAN_IFLAG_KEY = 0x02; + static const u8 WSWAN_IFLAG_RTC = 0x04; + static const u8 WSWAN_IFLAG_SRX = 0x08; + static const u8 WSWAN_IFLAG_LCMP = 0x10; + static const u8 WSWAN_IFLAG_VBLTMR = 0x20; + static const u8 WSWAN_IFLAG_VBL = 0x40; + static const u8 WSWAN_IFLAG_HBLTMR = 0x80; + + // Interrupts + static const u8 WSWAN_INT_STX = 0; + static const u8 WSWAN_INT_KEY = 1; + static const u8 WSWAN_INT_RTC = 2; + static const u8 WSWAN_INT_SRX = 3; + static const u8 WSWAN_INT_LCMP = 4; + static const u8 WSWAN_INT_VBLTMR = 5; + static const u8 WSWAN_INT_VBL = 6; + static const u8 WSWAN_INT_HBLTMR = 7; + + static const u32 INTERNAL_EEPROM_SIZE = 1024; // 16kbit on WSC + static const u32 INTERNAL_EEPROM_SIZE_WS = 64; // 1kbit on WS + + enum enum_system { TYPE_WSWAN=0, TYPE_WSC }; + + struct sound_dma_t + { + u32 source; // Source address + u16 size; // Size + u8 enable; // Enabled + }; + + required_device<cpu_device> m_maincpu; + required_device<wswan_video_device> m_vdp; + required_device<wswan_sound_device> m_sound; + required_device<ws_cart_slot_device> m_cart; + + u8 m_ws_portram[256]; + u8 m_internal_eeprom[INTERNAL_EEPROM_SIZE * 2]; + u8 m_system_type; + sound_dma_t m_sound_dma; + u8 m_bios_disabled; + u8 m_rotate; + + required_memory_region m_region_maincpu; + required_ioport m_cursx; + required_ioport m_cursy; + required_ioport m_buttons; + + u8 bios_r(offs_t offset); + u8 port_r(offs_t offset); + void port_w(offs_t offset, u8 data); + + void set_irq_line(int irq); + void dma_sound_cb(); + void common_start(); + virtual void machine_start() override; + virtual void machine_reset() override; + void palette(palette_device &palette) const; + + void io_map(address_map &map); + void mem_map(address_map &map); + void snd_map(address_map &map); + + void register_save(); + void handle_irqs(); + void clear_irq_line(int irq); + virtual u16 get_internal_eeprom_address(); +}; + +class wscolor_state : public wswan_state +{ +public: + using wswan_state::wswan_state; + void wscolor(machine_config &config); + +protected: + virtual void machine_start() override; + void mem_map(address_map &map); + void palette(palette_device &palette) const; + virtual u16 get_internal_eeprom_address() override; +}; + +static const uint8_t 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 +}; + +void wswan_state::mem_map(address_map &map) { map(0x00000, 0x03fff).rw(m_vdp, FUNC(wswan_video_device::vram_r), FUNC(wswan_video_device::vram_w)); // 16kb RAM / 4 colour tiles map(0x04000, 0x0ffff).noprw(); // nothing - //map(0x10000, 0xeffff) // cart range, setup at machine_start map(0xf0000, 0xfffff).r(FUNC(wswan_state::bios_r)); } -void wscolor_state::wscolor_mem(address_map &map) + +void wscolor_state::mem_map(address_map &map) { - map(0x00000, 0x0ffff).rw("vdp", FUNC(wswan_video_device::vram_r), FUNC(wswan_video_device::vram_w)); // 16kb RAM / 4 colour tiles, 16 colour tiles + palettes - //map(0x10000, 0xeffff) // cart range, setup at machine_start + map(0x00000, 0x0ffff).rw(m_vdp, FUNC(wswan_video_device::vram_r), FUNC(wswan_video_device::vram_w)); // 16kb RAM / 4 colour tiles, 16 colour tiles + palettes map(0xf0000, 0xfffff).r(FUNC(wscolor_state::bios_r)); } -void wswan_state::wswan_io(address_map &map) + +void wswan_state::io_map(address_map &map) { map(0x00, 0xff).rw(FUNC(wswan_state::port_r), FUNC(wswan_state::port_w)); // I/O ports } -void wswan_state::wswan_snd(address_map &map) + +void wswan_state::snd_map(address_map &map) { map(0x00000, 0x03fff).r(m_vdp, FUNC(wswan_video_device::vram_r)); } + static INPUT_PORTS_START( wswan ) PORT_START("CURSX") - PORT_BIT( 0x1, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("X1 - Up") - PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("X3 - Down") PORT_BIT( 0x8, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("X4 - Left") + PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("X3 - Down") PORT_BIT( 0x2, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("X2 - Right") + PORT_BIT( 0x1, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("X1 - Up") PORT_START("BUTTONS") - PORT_BIT( 0x2, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start") - PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Button A") PORT_BIT( 0x8, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Button B") + PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Button A") + PORT_BIT( 0x2, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start") PORT_START("CURSY") - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y1 - Up") PORT_CODE(KEYCODE_W) - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y3 - Down") PORT_CODE(KEYCODE_S) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y4 - Left") PORT_CODE(KEYCODE_A) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y3 - Down") PORT_CODE(KEYCODE_S) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y2 - Right") PORT_CODE(KEYCODE_D) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y1 - Up") PORT_CODE(KEYCODE_W) INPUT_PORTS_END static GFXDECODE_START( gfx_wswan ) GFXDECODE_END + /* WonderSwan can display 16 shades of grey */ -void wswan_state::wswan_palette(palette_device &palette) const +void wswan_state::palette(palette_device &palette) const { for (int i = 0; i < 16; i++) { @@ -99,7 +228,8 @@ void wswan_state::wswan_palette(palette_device &palette) const } } -void wscolor_state::wscolor_palette(palette_device &palette) const + +void wscolor_state::palette(palette_device &palette) const { for (int i = 0; i < 4096; i++) { @@ -110,6 +240,7 @@ void wscolor_state::wscolor_palette(palette_device &palette) const } } + static void wswan_cart(device_slot_interface &device) { device.option_add_internal("ws_rom", WS_ROM_STD); @@ -117,16 +248,17 @@ static void wswan_cart(device_slot_interface &device) device.option_add_internal("ws_eeprom", WS_ROM_EEPROM); } + void wswan_state::wswan(machine_config &config) { - /* Basic machine hardware */ + // Basic machine hardware V30MZ(config, m_maincpu, 3.072_MHz_XTAL); - m_maincpu->set_addrmap(AS_PROGRAM, &wswan_state::wswan_mem); - m_maincpu->set_addrmap(AS_IO, &wswan_state::wswan_io); + m_maincpu->set_addrmap(AS_PROGRAM, &wswan_state::mem_map); + m_maincpu->set_addrmap(AS_IO, &wswan_state::io_map); WSWAN_VIDEO(config, m_vdp, 0); m_vdp->set_screen("screen"); - m_vdp->set_vdp_type(VDP_TYPE_WSWAN); + m_vdp->set_vdp_type(wswan_video_device::VDP_TYPE_WSWAN); m_vdp->set_irq_callback(FUNC(wswan_state::set_irq_line)); m_vdp->set_dmasnd_callback(FUNC(wswan_state::dma_sound_cb)); @@ -136,68 +268,622 @@ void wswan_state::wswan(machine_config &config) screen.set_screen_update("vdp", FUNC(wswan_video_device::screen_update)); // screen.set_size(WSWAN_X_PIXELS, WSWAN_Y_PIXELS); // screen.set_visarea(0*8, WSWAN_X_PIXELS - 1, 0, WSWAN_Y_PIXELS - 1); - screen.set_raw(3.072_MHz_XTAL, 256, 0, WSWAN_X_PIXELS, 159, 0, WSWAN_Y_PIXELS); + screen.set_raw(3.072_MHz_XTAL, 256, 0, wswan_video_device::WSWAN_X_PIXELS, 159, 0, wswan_video_device::WSWAN_Y_PIXELS); screen.set_palette("palette"); config.set_default_layout(layout_wswan); config.set_maximum_quantum(attotime::from_hz(60)); - NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1); + NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); GFXDECODE(config, "gfxdecode", "palette", gfx_wswan); - PALETTE(config, "palette", FUNC(wswan_state::wswan_palette), 16); + PALETTE(config, "palette", FUNC(wswan_state::palette), 16); - /* sound hardware */ + // sound hardware SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); WSWAN_SND(config, m_sound, 3.072_MHz_XTAL); - m_sound->set_addrmap(0, &wswan_state::wswan_snd); + m_sound->set_addrmap(0, &wswan_state::snd_map); m_sound->add_route(0, "lspeaker", 0.50); m_sound->add_route(1, "rspeaker", 0.50); - /* cartridge */ + // cartridge WS_CART_SLOT(config, m_cart, 3.072_MHz_XTAL / 8, wswan_cart, nullptr); - /* software lists */ + // software lists SOFTWARE_LIST(config, "cart_list").set_original("wswan"); SOFTWARE_LIST(config, "wsc_list").set_compatible("wscolor"); SOFTWARE_LIST(config, "pc2_list").set_compatible("pockchalv2"); } + void wscolor_state::wscolor(machine_config &config) { wswan(config); - m_maincpu->set_addrmap(AS_PROGRAM, &wscolor_state::wscolor_mem); + m_maincpu->set_addrmap(AS_PROGRAM, &wscolor_state::mem_map); - m_vdp->set_vdp_type(VDP_TYPE_WSC); + m_vdp->set_vdp_type(wswan_video_device::VDP_TYPE_WSC); auto &palette(*subdevice<palette_device>("palette")); palette.set_entries(4096); - palette.set_init(FUNC(wscolor_state::wscolor_palette)); + palette.set_init(FUNC(wscolor_state::palette)); - /* software lists */ + // software lists config.device_remove("wsc_list"); SOFTWARE_LIST(config.replace(), "cart_list").set_original("wscolor"); SOFTWARE_LIST(config, "ws_list").set_compatible("wswan"); } + +void wswan_state::handle_irqs() +{ + if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_HBLTMR) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_HBLTMR); // V30MZ + } + else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBL) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBL); // V30MZ + } + else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBLTMR) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBLTMR); // V30MZ + } + else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_LCMP) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_LCMP); // V30MZ + } + else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_SRX) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_SRX); // V30MZ + } + else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_RTC) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_RTC); // V30MZ + } + else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_KEY) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_KEY); // V30MZ + } + else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_STX) + { + m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_STX); // V30MZ + } + else + { + m_maincpu->set_input_line(0, CLEAR_LINE); + } +} + + +void wswan_state::set_irq_line(int irq) +{ + if (m_ws_portram[0xb2] & irq) + { + m_ws_portram[0xb6] |= irq; + handle_irqs(); + } +} + + +void wswan_state::dma_sound_cb() +{ + if ((m_sound_dma.enable & 0x88) == 0x80) + { + address_space &space = m_maincpu->space(AS_PROGRAM); + /* TODO: Output sound DMA byte */ + port_w(0x89, space.read_byte(m_sound_dma.source)); + m_sound_dma.size--; + m_sound_dma.source = (m_sound_dma.source + 1) & 0x0fffff; + if (m_sound_dma.size == 0) + { + m_sound_dma.enable &= 0x7f; + } + } +} + + +void wswan_state::clear_irq_line(int irq) +{ + m_ws_portram[0xb6] &= ~irq; + handle_irqs(); +} + + +void wswan_state::register_save() +{ + save_item(NAME(m_ws_portram)); + save_item(NAME(m_internal_eeprom)); + save_item(NAME(m_bios_disabled)); + save_item(NAME(m_rotate)); + + save_item(NAME(m_sound_dma.source)); + save_item(NAME(m_sound_dma.size)); + save_item(NAME(m_sound_dma.enable)); + + if (m_cart->exists()) + m_cart->save_nvram(); +} + + +void wswan_state::common_start() +{ + register_save(); + + if (m_cart->exists()) + { + // ROM + m_maincpu->space(AS_PROGRAM).install_read_handler(0x20000, 0x2ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom20))); + m_maincpu->space(AS_PROGRAM).install_read_handler(0x30000, 0x3ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom30))); + m_maincpu->space(AS_PROGRAM).install_read_handler(0x40000, 0xeffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom40))); + + // SRAM + if (m_cart->get_type() == WS_SRAM) + { + m_maincpu->space(AS_PROGRAM).install_read_handler(0x10000, 0x1ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_ram))); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x10000, 0x1ffff, write8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::write_ram))); + } + } +} + + +void wswan_state::machine_start() +{ + common_start(); + subdevice<nvram_device>("nvram")->set_base(m_internal_eeprom, INTERNAL_EEPROM_SIZE_WS * 2); + m_system_type = TYPE_WSWAN; +} + + +void wscolor_state::machine_start() +{ + common_start(); + subdevice<nvram_device>("nvram")->set_base(m_internal_eeprom, INTERNAL_EEPROM_SIZE * 2); + m_system_type = TYPE_WSC; +} + + +void wswan_state::machine_reset() +{ + m_bios_disabled = 0; + + if (m_cart->exists()) + m_rotate = m_cart->get_is_rotated(); + else + m_rotate = 0; + + /* Intialize ports */ + memcpy(m_ws_portram, ws_portram_init, 256); + + render_target *target = machine().render().first_target(); + target->set_view(m_rotate); + + /* Initialize sound DMA */ + memset(&m_sound_dma, 0, sizeof(m_sound_dma)); +} + + +u8 wswan_state::bios_r(offs_t offset) +{ + if (!m_bios_disabled) + return m_region_maincpu->base()[offset & (m_region_maincpu->bytes() - 1)]; + else + return m_cart->read_rom40(offset + 0xb0000); +} + + +u8 wswan_state::port_r(offs_t offset) +{ + u8 value = m_ws_portram[offset]; + + if (offset != 2) + logerror("PC=%X: port read %02X\n", m_maincpu->pc(), offset); + + if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0)) + return m_vdp->reg_r(offset); + + switch (offset) + { + 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 0x60: + value = m_vdp->reg_r(offset); + break; + case 0xa0: // Hardware type + // Bit 0 - Disable/enable Bios + // Bit 1 - Determine mono/color + // Bit 2 - Unknown, used to determine color/crystal + // Bit 3 - Unknown + // Bit 7 - Checked during start up, expects bit 7 set + value = value & ~ 0x02; + if (m_system_type == TYPE_WSC) + value |= 2; + value |= 0x80; + 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 + value = value & 0xf0; + switch (value) + { + case 0x10: // Read Y cursors: Y1 - Y2 - Y3 - Y4 + { + u8 input = m_cursy->read(); + if (m_rotate) // reorient controls if the console is rotated + { + if (input & 0x01) value |= 0x02; + if (input & 0x02) value |= 0x04; + if (input & 0x04) value |= 0x08; + if (input & 0x08) value |= 0x01; + } + else + value = value | input; + } + break; + case 0x20: // Read X cursors: X1 - X2 - X3 - X4 + { + u8 input = m_cursx->read(); + if (m_rotate) // reorient controls if the console is rotated + { + if (input & 0x01) value |= 0x02; + if (input & 0x02) value |= 0x04; + if (input & 0x04) value |= 0x08; + if (input & 0x08) value |= 0x01; + } + else + value = value | input; + } + break; + case 0x40: // Read buttons: START - A - B + value = value | m_buttons->read(); + break; + } + break; + case 0xc0: + case 0xc1: + case 0xc2: + case 0xc3: + case 0xc4: // Cartridge EEPROM data + case 0xc5: // Cartridge EEPROM data + case 0xc6: + case 0xc7: + case 0xc8: + case 0xc9: + case 0xca: + case 0xcb: // RTC data + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: + value = m_cart->read_io(offset & 0x0f); + break; + } + + return value; +} + + +void wswan_state::port_w(offs_t offset, u8 data) +{ + address_space &mem = m_maincpu->space(AS_PROGRAM); + logerror("PC=%X: port write %02X <- %02X\n", m_maincpu->pc(), offset, data); + + if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0)) + { + m_vdp->reg_w(offset, data); + return; + } + + switch (offset) + { + case 0x40: // DMA source address (low) + case 0x41: // DMA source address (high) + case 0x42: // DMA source bank + case 0x43: // DMA destination bank + case 0x44: // DMA destination address (low) + case 0x45: // DMA destination address (high) + case 0x46: // Size of copied data (low) + case 0x47: // Size of copied data (high) + break; + case 0x48: // DMA control + // Bit 0-6 - Unknown + // Bit 7 - DMA stop/start + if (data & 0x80) + { + u32 src, dst; + u16 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 MAME_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) + m_sound_dma.source = (m_sound_dma.source & 0x0fff00) | data; + break; + case 0x4b: // Sound DMA source address (high) + 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) + m_sound_dma.size = (m_sound_dma.size & 0xff00) | data; + break; + case 0x4f: // Sound DMA transfer size (high) + 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: + m_vdp->reg_w(offset, data); + break; + case 0x80: // Audio 1 freq (lo) + case 0x81: // Audio 1 freq (hi) + case 0x82: // Audio 2 freq (lo) + case 0x83: // Audio 2 freq (hi) + case 0x84: // Audio 3 freq (lo) + case 0x85: // Audio 3 freq (hi) + case 0x86: // Audio 4 freq (lo) + case 0x87: // Audio 4 freq (hi) + 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 + case 0x8d: // 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) + 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 + m_sound->port_w(offset, data); + break; + case 0x9E: // WSC volume setting (0, 1, 2, 3) + break; + case 0xa0: // Hardware type/system control + // Bit 0 - Enable cartridge slot and/or disable bios + // Bit 1 - Hardware type: 0 = WS, 1 = WSC + // Bit 2 - Unknown, written during boot + // Bit 3 - Unknown, written during boot + // Bit 4-6 - Unknown + // Bit 7 - Unknown, read during boot + if ((data & 0x01) && !m_bios_disabled) + m_bios_disabled = 1; + break; + + case 0xb0: // Interrupt base vector + break; + case 0xb1: // 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 + 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 + 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 + clear_irq_line(data); + data = m_ws_portram[0xb6]; + break; + case 0xba: // Internal EEPROM data (low) + case 0xbb: // Internal EEPROM data (high) + break; + case 0xbc: // Internal EEPROM address (low) + // (WS) Bit 0-5 = Internal EEPROM address + // (WSC) Bit 0-7 - Internal EEPROM address bit 1-8 + case 0xbd: // Internal EEPROM address (high) + // (WSC) Bit 0 - Internal EEPROM address bit 9(?) + // Bit 1-7 - Unknown + break; + case 0xbe: // Internal EEPROM command/status + // 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) + { + u16 addr = get_internal_eeprom_address(); + m_internal_eeprom[addr] = m_ws_portram[0xba]; + m_internal_eeprom[addr + 1] = m_ws_portram[0xbb]; + data |= 0x02; + } + else if ( data & 0x10 ) + { + u16 addr = get_internal_eeprom_address(); + 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 $40000-$fffff + case 0xc1: // SRAM bank + case 0xc2: // ROM bank $20000-$2ffff + case 0xc3: // ROM bank $30000-$3ffff + case 0xc4: + case 0xc5: + case 0xc6: // EEPROM address / command + case 0xc7: // EEPROM address / command + case 0xc8: // EEPROM command + case 0xc9: + case 0xca: // RTC command + case 0xcb: // RTC data + case 0xcc: + case 0xcd: + case 0xce: + case 0xcf: + m_cart->write_io(offset & 0x0f, data); + break; + default: + logerror( "Write to unsupported port: %X - %X\n", offset, data ); + break; + } + + // Update the port value + m_ws_portram[offset] = data; +} + + +u16 wswan_state::get_internal_eeprom_address() { + return (m_ws_portram[0xbc] & 0x3f) << 1; +} + + +u16 wscolor_state::get_internal_eeprom_address() { + return (((m_ws_portram[0xbd] << 8) | m_ws_portram[0xbc]) & 0x1FF) << 1; +} + /*************************************************************************** Game driver(s) ***************************************************************************/ -ROM_START( wswan ) - ROM_REGION( 0x100000, "maincpu", ROMREGION_ERASEFF ) -// ROM_LOAD( "ws_bios.bin", 0x0000, 0x0001, NO_DUMP ) +ROM_START(wswan) + ROM_REGION(0x1000, "maincpu", 0) + ROM_LOAD("boot.rom", 0x0000, 0x1000, CRC(7f35f890) SHA1(4015bcacea76bb0b5bbdb13c5358f7e1abb986a1)) + + ROM_REGION(0x80, "nvram", 0) + // Need a dump from an original new unit + // Empty file containing just the name 'WONDERSAN' + ROM_LOAD("internal_eeprom.ws", 0x00, 0x80, BAD_DUMP CRC(b1dff316) SHA1(7b76c3d59c9add9501f95e8bfc34427773fcbd28)) ROM_END -ROM_START( wscolor ) - ROM_REGION( 0x100000, "maincpu", ROMREGION_ERASEFF ) -// ROM_LOAD( "wsc_bios.bin", 0x0000, 0x0001, NO_DUMP ) +ROM_START(wscolor) + ROM_REGION(0x2000, "maincpu", 0) + ROM_LOAD("boot.rom", 0x0000, 0x2000, CRC(cb06d9c3) SHA1(c5ad0b8af45d762662a69f50b64161b9c8919efb)) + + ROM_REGION(0x800, "nvram", 0) + // Need a dump from an original new unit + // Empty file containing just the name 'WONDERSAN' + ROM_LOAD("internal_eeprom.wsc", 0x000, 0x800, BAD_DUMP CRC(9e29725c) SHA1(a903c2cb5f4bb94b67326ff87a2d91605dceffff)) ROM_END // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME diff --git a/src/mame/includes/wswan.h b/src/mame/includes/wswan.h deleted file mode 100644 index 2657e33e3c3..00000000000 --- a/src/mame/includes/wswan.h +++ /dev/null @@ -1,120 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Wilbert Pol -/***************************************************************************** - * - * includes/wswan.h - * - ****************************************************************************/ -#ifndef MAME_INCLUDES_WSWAN_H -#define MAME_INCLUDES_WSWAN_H - -#pragma once - -#define WSWAN_TYPE_MONO 0 -#define WSWAN_TYPE_COLOR 1 - -#define INTERNAL_EEPROM_SIZE 1024 - -#include "cpu/v30mz/v30mz.h" -#include "machine/nvram.h" -#include "audio/wswan.h" -#include "video/wswan.h" -#include "bus/wswan/slot.h" -#include "bus/wswan/rom.h" -#include "emupal.h" - - -class wswan_state : public driver_device -{ -public: - wswan_state(const machine_config &mconfig, device_type type, const char *tag) : - driver_device(mconfig, type, tag), - m_maincpu(*this, "maincpu"), - m_vdp(*this, "vdp"), - m_sound(*this, "custom"), - m_cart(*this, "cartslot"), - m_cursx(*this, "CURSX"), - m_cursy(*this, "CURSY"), - m_buttons(*this, "BUTTONS") - { } - - void wswan(machine_config &config); - -protected: - /* Interrupt flags */ - static const uint8_t WSWAN_IFLAG_STX = 0x01; - static const uint8_t WSWAN_IFLAG_KEY = 0x02; - static const uint8_t WSWAN_IFLAG_RTC = 0x04; - static const uint8_t WSWAN_IFLAG_SRX = 0x08; - static const uint8_t WSWAN_IFLAG_LCMP = 0x10; - static const uint8_t WSWAN_IFLAG_VBLTMR = 0x20; - static const uint8_t WSWAN_IFLAG_VBL = 0x40; - static const uint8_t WSWAN_IFLAG_HBLTMR = 0x80; - - /* Interrupts */ - static const uint8_t WSWAN_INT_STX = 0; - static const uint8_t WSWAN_INT_KEY = 1; - static const uint8_t WSWAN_INT_RTC = 2; - static const uint8_t WSWAN_INT_SRX = 3; - static const uint8_t WSWAN_INT_LCMP = 4; - static const uint8_t WSWAN_INT_VBLTMR = 5; - static const uint8_t WSWAN_INT_VBL = 6; - static const uint8_t WSWAN_INT_HBLTMR = 7; - - struct SoundDMA - { - uint32_t source; /* Source address */ - uint16_t size; /* Size */ - uint8_t enable; /* Enabled */ - }; - - required_device<cpu_device> m_maincpu; - required_device<wswan_video_device> m_vdp; - required_device<wswan_sound_device> m_sound; - required_device<ws_cart_slot_device> m_cart; - - uint8_t m_ws_portram[256]; - uint8_t m_internal_eeprom[INTERNAL_EEPROM_SIZE]; - uint8_t m_system_type; - SoundDMA m_sound_dma; - std::unique_ptr<uint8_t[]> m_ws_bios_bank; - uint8_t m_bios_disabled; - uint8_t m_rotate; - - required_ioport m_cursx; - required_ioport m_cursy; - required_ioport m_buttons; - - uint8_t bios_r(offs_t offset); - uint8_t port_r(offs_t offset); - void port_w(offs_t offset, uint8_t data); - - void set_irq_line(int irq); - void dma_sound_cb(); - void common_start(); - virtual void machine_start() override; - virtual void machine_reset() override; - void wswan_palette(palette_device &palette) const; - - void wswan_io(address_map &map); - void wswan_mem(address_map &map); - void wswan_snd(address_map &map); - - void register_save(); - void handle_irqs(); - void clear_irq_line(int irq); -}; - -class wscolor_state : public wswan_state -{ -public: - using wswan_state::wswan_state; - void wscolor(machine_config &config); - -protected: - virtual void machine_start() override; - void wscolor_mem(address_map &map); - void wscolor_palette(palette_device &palette) const; -}; - -#endif // MAME_INCLUDES_WSWAN_H diff --git a/src/mame/machine/wswan.cpp b/src/mame/machine/wswan.cpp deleted file mode 100644 index c8a942e1a6e..00000000000 --- a/src/mame/machine/wswan.cpp +++ /dev/null @@ -1,664 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Anthony Kruize,Wilbert Pol -/*************************************************************************** - - 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 "emu.h" -#include "includes/wswan.h" -#include "render.h" - -#define INTERNAL_EEPROM_SIZE 1024 - -enum enum_system { TYPE_WSWAN=0, TYPE_WSC }; - - -static const uint8_t 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_t 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 -}; - -void wswan_state::handle_irqs() -{ - if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_HBLTMR) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_HBLTMR); // V30MZ - } - else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBL) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBL); // V30MZ - } - else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBLTMR) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBLTMR); // V30MZ - } - else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_LCMP) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_LCMP); // V30MZ - } - else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_SRX) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_SRX); // V30MZ - } - else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_RTC) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_RTC); // V30MZ - } - else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_KEY) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_KEY); // V30MZ - } - else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_STX) - { - m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_STX); // V30MZ - } - else - { - m_maincpu->set_input_line(0, CLEAR_LINE); - } -} - -void wswan_state::set_irq_line(int irq) -{ - if (m_ws_portram[0xb2] & irq) - { - m_ws_portram[0xb6] |= irq; - handle_irqs(); - } -} - -void wswan_state::dma_sound_cb() -{ - if ((m_sound_dma.enable & 0x88) == 0x80) - { - address_space &space = m_maincpu->space(AS_PROGRAM); - /* TODO: Output sound DMA byte */ - port_w(0x89, space.read_byte(m_sound_dma.source)); - m_sound_dma.size--; - m_sound_dma.source = (m_sound_dma.source + 1) & 0x0fffff; - if (m_sound_dma.size == 0) - { - m_sound_dma.enable &= 0x7F; - } - } -} - -void wswan_state::clear_irq_line(int irq) -{ - m_ws_portram[0xb6] &= ~irq; - handle_irqs(); -} - -void wswan_state::register_save() -{ - save_item(NAME(m_ws_portram)); - save_item(NAME(m_internal_eeprom)); - save_item(NAME(m_bios_disabled)); - save_item(NAME(m_rotate)); - - save_item(NAME(m_sound_dma.source)); - save_item(NAME(m_sound_dma.size)); - save_item(NAME(m_sound_dma.enable)); - - if (m_cart->exists()) - m_cart->save_nvram(); -} - -void wswan_state::common_start() -{ - m_ws_bios_bank = std::make_unique<uint8_t[]>(0x10000); - memcpy(m_ws_bios_bank.get() + 0xffc0, ws_fake_bios_code, 0x40); - - register_save(); - - subdevice<nvram_device>("nvram")->set_base(m_internal_eeprom, INTERNAL_EEPROM_SIZE); - - if (m_cart->exists()) - { - // ROM - m_maincpu->space(AS_PROGRAM).install_read_handler(0x20000, 0x2ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom20))); - m_maincpu->space(AS_PROGRAM).install_read_handler(0x30000, 0x3ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom30))); - m_maincpu->space(AS_PROGRAM).install_read_handler(0x40000, 0xeffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom40))); - - // SRAM - if (m_cart->get_type() == WS_SRAM) - { - m_maincpu->space(AS_PROGRAM).install_read_handler(0x10000, 0x1ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_ram))); - m_maincpu->space(AS_PROGRAM).install_write_handler(0x10000, 0x1ffff, write8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::write_ram))); - } - } -} - -void wswan_state::machine_start() -{ - common_start(); - m_system_type = TYPE_WSWAN; -} - -void wscolor_state::machine_start() -{ - common_start(); - m_system_type = TYPE_WSC; -} - -void wswan_state::machine_reset() -{ - m_bios_disabled = 0; - - if (m_cart->exists()) - m_rotate = m_cart->get_is_rotated(); - else - m_rotate = 0; - - /* Intialize ports */ - memcpy(m_ws_portram, ws_portram_init, 256); - - render_target *target = machine().render().first_target(); - target->set_view(m_rotate); - - /* Initialize sound DMA */ - memset(&m_sound_dma, 0, sizeof(m_sound_dma)); -} - -uint8_t wswan_state::bios_r(offs_t offset) -{ - if (!m_bios_disabled) - return m_ws_bios_bank[offset]; - else - return m_cart->read_rom40(offset + 0xb0000); -} - -uint8_t wswan_state::port_r(offs_t offset) -{ - uint8_t value = m_ws_portram[offset]; - - if (offset != 2) - logerror("PC=%X: port read %02X\n", m_maincpu->pc(), offset); - - if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0)) - return m_vdp->reg_r(offset); - - switch (offset) - { - 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 0x60: - value = m_vdp->reg_r(offset); - 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 0xc0: - case 0xc1: - case 0xc2: - case 0xc3: - case 0xc4: // EEPROM data - case 0xc5: // EEPROM data - case 0xc6: - case 0xc7: - case 0xc8: - case 0xc9: - case 0xca: - case 0xcb: // RTC data - case 0xcc: - case 0xcd: - case 0xce: - case 0xcf: - value = m_cart->read_io(offset & 0x0f); - break; - } - - return value; -} - -void wswan_state::port_w(offs_t offset, uint8_t data) -{ - address_space &mem = m_maincpu->space(AS_PROGRAM); - uint8_t input; - logerror("PC=%X: port write %02X <- %02X\n", m_maincpu->pc(), offset, data); - - if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0)) - { - m_vdp->reg_w(offset, data); - return; - } - - switch (offset) - { - 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_t src, dst; - uint16_t 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 MAME_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: - m_vdp->reg_w(offset, data); - 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 - */ - m_sound->port_w(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; - 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 = m_cursy->read(); - if (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 = m_cursx->read(); - if (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 | m_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 - */ - 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_t 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_t 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 $40000-$fffff - case 0xc1: // SRAM bank - case 0xc2: // ROM bank $20000-$2ffff - case 0xc3: // ROM bank $30000-$3ffff - case 0xc4: - case 0xc5: - case 0xc6: // EEPROM address / command - case 0xc7: // EEPROM address / command - case 0xc8: // EEPROM command - case 0xc9: - case 0xca: // RTC command - case 0xcb: // RTC data - case 0xcc: - case 0xcd: - case 0xce: - case 0xcf: - m_cart->write_io(offset & 0x0f, data); - break; - default: - logerror( "Write to unsupported port: %X - %X\n", offset, data ); - break; - } - - /* Update the port value */ - m_ws_portram[offset] = data; -} diff --git a/src/mame/video/wswan.cpp b/src/mame/video/wswan.cpp index 258925e2058..a6866091546 100644 --- a/src/mame/video/wswan.cpp +++ b/src/mame/video/wswan.cpp @@ -9,7 +9,8 @@ TODO: - remove the redundant parts of m_regs - - split the Color VDP from the Mono VDP? + - split the Color VDP from the Mono VDP + - Add support for WSC high/low contrast (register 14, bit 1) ***************************************************************************/ @@ -804,8 +805,7 @@ void wswan_video_device::refresh_scanline() rectangle rec(0, WSWAN_X_PIXELS, m_current_line, m_current_line); if (m_lcd_control) { - /* Not sure if these background color checks and settings are correct */ - if (m_color_mode && m_colors_16) + if (m_color_mode) m_bitmap.fill(m_pal[m_bg_control >> 4][m_bg_control & 0x0f], rec); else m_bitmap.fill(m_main_palette[m_bg_control & 0x07], rec); @@ -1007,7 +1007,8 @@ void wswan_video_device::reg_w(offs_t offset, uint8_t data) break; case 0x14: // LCD control // Bit 0 - LCD enable - // Bit 1-7 - Unknown + // Bit 1 - WSC only, brightness low/high + // Bit 2-7 - Unknown m_lcd_control = data; break; case 0x15: // LCD icons diff --git a/src/mame/video/wswan.h b/src/mame/video/wswan.h index a7df4401e77..0ca4b6d3c1d 100644 --- a/src/mame/video/wswan.h +++ b/src/mame/video/wswan.h @@ -16,20 +16,6 @@ #pragma once - -enum -{ - VDP_TYPE_WSWAN = 0, - VDP_TYPE_WSC -}; - -#define WSWAN_X_PIXELS (28*8) -#define WSWAN_Y_PIXELS (18*8) - - -#define WSWAN_VIDEO_IRQ_CB_MEMBER(_name) void _name(int irq) -#define WSWAN_VIDEO_DMASND_CB_MEMBER(_name) void _name() - class wswan_video_device : public device_t, public device_video_interface { public: @@ -51,6 +37,15 @@ public: uint8_t reg_r(offs_t offset); void reg_w(offs_t offset, uint8_t data); + enum + { + VDP_TYPE_WSWAN = 0, + VDP_TYPE_WSC + }; + + static const u16 WSWAN_X_PIXELS = (28*8); + static const u16 WSWAN_Y_PIXELS = (18*8); + protected: // device-level overrides virtual void device_start() override; |