diff options
author | 2025-04-09 06:30:15 +0900 | |
---|---|---|
committer | 2025-04-09 07:30:15 +1000 | |
commit | 7214b1d7485050a6bb227cc7a7d2d4a6548bda6b (patch) | |
tree | 3398f841f2202528cc98401976cef441965350bc | |
parent | be3a4c60dc68c20ece1360ddf12130493489d992 (diff) |
bandai/wswan.cpp, bandai/wswan_v.cpp, shared/wswansound.cpp, virtual/vgmplay.cpp: Updates/Cleanups: (#13469)
* bandai/wswan.cpp:
- Remove unused graphics decoding layout.
- Fixed sound DMA, implemented DMA direction, moved DMA-related code into WonderSwan color state class.
- Make some variables constant, reformatted code.
* bandai/wswan_v.cpp:
- Split wonderswan color VDP device class into a separate class.
- Move palette functionality from system driver into VDP device.
- Corrected VRAM size.
- Use bool for Boolean values.
- Use logmacro.h helpers for configurable logging.
- Reduced duplicated code.
- Remove unused variables and code, reduced duplication, reformatted code.
* shared/wswansound.cpp:
- Implemented Hypervoice.
- Added mono speaker/stereo headphones selection.
- Fixed some emulation issues and corrected output rate and volume.
- Use logmacro.h helpers for configurable logging.
* virtual/vgmplay.cpp: Added Hypervoice support and stereo output for WonderSwan sound.
-rw-r--r-- | src/mame/bandai/wswan.cpp | 618 | ||||
-rw-r--r-- | src/mame/bandai/wswan_v.cpp | 836 | ||||
-rw-r--r-- | src/mame/bandai/wswan_v.h | 84 | ||||
-rw-r--r-- | src/mame/shared/wswansound.cpp | 391 | ||||
-rw-r--r-- | src/mame/shared/wswansound.h | 111 | ||||
-rw-r--r-- | src/mame/virtual/vgmplay.cpp | 4 |
6 files changed, 1079 insertions, 965 deletions
diff --git a/src/mame/bandai/wswan.cpp b/src/mame/bandai/wswan.cpp index 2481df8174f..fc149da6ce1 100644 --- a/src/mame/bandai/wswan.cpp +++ b/src/mame/bandai/wswan.cpp @@ -35,7 +35,6 @@ #include "machine/nvram.h" #include "bus/wswan/slot.h" #include "bus/wswan/rom.h" -#include "emupal.h" #include "render.h" #include "screen.h" #include "softlist_dev.h" @@ -45,6 +44,19 @@ #include <algorithm> +#define LOG_UNKNOWN (1 << 1) +#define LOG_EEPROM (1 << 2) +#define LOG_DMA (1 << 3) + +#define LOG_ALL (LOG_UNKNOWN | LOG_EEPROM | LOG_DMA) + +#define VERBOSE (0) + +#include "logmacro.h" + +#define LOGUNKNOWN(...) LOGMASKED(LOG_UNKNOWN, __VA_ARGS__) +#define LOGEEPROM(...) LOGMASKED(LOG_EEPROM, __VA_ARGS__) +#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__) namespace { @@ -61,13 +73,19 @@ public: m_cursx(*this, "CURSX"), m_cursy(*this, "CURSY"), m_buttons(*this, "BUTTONS"), + m_sound_output(*this, "SOUND_OUTPUT"), m_icons(*this, "icon%u", 0U) { } void wswan(machine_config &config); void pockchv2(machine_config &config); + DECLARE_INPUT_CHANGED_MEMBER(sound_output_changed); + protected: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + void wswan_base(machine_config &config); // Interrupt flags @@ -96,32 +114,24 @@ protected: // Labeled 12.3FXA on wonderswan color pcb static constexpr XTAL X1 = 12.288_MHz_XTAL; - enum enum_system { TYPE_WSWAN=0, TYPE_WSC }; - - struct sound_dma_t - { - sound_dma_t() { } - - u32 source = 0; // Source address - u16 size = 0; // Size - u8 enable = 0; // Enabled - }; + enum enum_system { TYPE_WSWAN = 0, TYPE_WSC }; required_device<v30mz_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; + required_memory_region m_region_maincpu; + required_ioport m_cursx; + required_ioport m_cursy; + required_ioport m_buttons; + required_ioport m_sound_output; + output_finder<6> m_icons; + u16 m_ws_portram[128] = { }; u8 m_internal_eeprom[INTERNAL_EEPROM_SIZE * 2] = { }; u8 m_system_type = 0; - sound_dma_t m_sound_dma; - u16 m_dma_source_offset = 0; - u16 m_dma_source_segment = 0; - u16 m_dma_destination = 0; - u16 m_dma_length = 0; - u16 m_dma_control = 0; - u8 m_bios_disabled = 0; + bool m_bios_disabled = false; u8 m_rotate = 0; u32 m_vector = 0; u8 m_sys_control = 0; @@ -135,48 +145,73 @@ protected: u8 m_internal_eeprom_command = 0; u8 m_keypad = 0; - required_memory_region m_region_maincpu; - required_ioport m_cursx; - required_ioport m_cursy; - required_ioport m_buttons; - output_finder<6> m_icons; - u16 bios_r(offs_t offset, u16 mem_mask); u16 port_r(offs_t offset, u16 mem_mask); void port_w(offs_t offset, u16 data, u16 mem_mask); void set_irq_line(int irq); - void dma_sound_cb(); void common_start(); - virtual void machine_start() override ATTR_COLD; - virtual void machine_reset() override ATTR_COLD; - void palette(palette_device &palette) const; - void io_map(address_map &map) ATTR_COLD; - void mem_map(address_map &map) ATTR_COLD; - void snd_map(address_map &map) ATTR_COLD; - - void register_save(); void handle_irqs(); void clear_irq_line(int irq); virtual u16 get_internal_eeprom_address(); u32 get_vector() { return m_vector; } void set_icons(u8 data); void set_rotate_view(); + + void io_map(address_map &map) ATTR_COLD; + void mem_map(address_map &map) ATTR_COLD; + void snd_map(address_map &map) ATTR_COLD; }; class wscolor_state : public wswan_state { public: - using wswan_state::wswan_state; + wscolor_state(const machine_config &mconfig, device_type type, const char *tag) : + wswan_state(mconfig, type, tag), + m_dma_view(*this, "dma_view"), + m_hypervoice_view(*this, "hypervoice_view") + { } + void wscolor(machine_config &config); protected: virtual void machine_start() override ATTR_COLD; - void mem_map(address_map &map) ATTR_COLD; - void palette(palette_device &palette) const; + virtual void machine_reset() override ATTR_COLD; + virtual u16 get_internal_eeprom_address() override; + +private: + static constexpr u8 SOUND_DMA_DIV[4] = { 6, 4, 2, 1 }; + + memory_view m_dma_view; + memory_view m_hypervoice_view; + + struct sound_dma_t + { + emu_timer *timer = nullptr; // Timer + u32 source = 0; // Source address + u32 source_reload = 0; // Source address, Value for reload + u32 size = 0; // Size + u32 size_reload = 0; // Size, Value for reload + u8 control = 0; // Control + }; + sound_dma_t m_sound_dma; + u16 m_dma_source_offset = 0; + u16 m_dma_source_segment = 0; + u16 m_dma_destination = 0; + u16 m_dma_length = 0; + u16 m_dma_control = 0; + + u16 dma_r(offs_t offset, u16 mem_mask); + void dma_w(offs_t offset, u16 data, u16 mem_mask); + void color_mode_view_w(int state); + + TIMER_CALLBACK_MEMBER(sound_dma_cb); + + void io_map(address_map &map) ATTR_COLD; + void mem_map(address_map &map) ATTR_COLD; }; @@ -190,7 +225,7 @@ void wswan_state::mem_map(address_map &map) void wscolor_state::mem_map(address_map &map) { - 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(0x00000, 0x0ffff).rw(m_vdp, FUNC(wswan_video_device::vram_r), FUNC(wswan_video_device::vram_w)); // 16/64kb RAM / 4 colour tiles, 16 colour tiles + palettes map(0xf0000, 0xfffff).r(FUNC(wscolor_state::bios_r)); } @@ -201,6 +236,16 @@ void wswan_state::io_map(address_map &map) } +void wscolor_state::io_map(address_map &map) +{ + map(0x00, 0xff).rw(FUNC(wscolor_state::port_r), FUNC(wscolor_state::port_w)); // I/O ports + map(0x40, 0x53).view(m_dma_view); + m_dma_view[0](0x40, 0x53).rw(FUNC(wscolor_state::dma_r), FUNC(wscolor_state::dma_w)); + map(0x64, 0x6b).view(m_hypervoice_view); + m_hypervoice_view[0](0x64, 0x6b).rw(m_sound, FUNC(wswan_sound_device::hypervoice_r), FUNC(wswan_sound_device::hypervoice_w)); +} + + void wswan_state::snd_map(address_map &map) { map(0x00000, 0x03fff).r(m_vdp, FUNC(wswan_video_device::vram_r)); @@ -224,34 +269,12 @@ static INPUT_PORTS_START(wswan) 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::palette(palette_device &palette) const -{ - for (int i = 0; i < 16; i++) - { - u8 const shade = i * (256 / 16); - palette.set_pen_color(15 - i, shade, shade, shade); - } -} - - -void wscolor_state::palette(palette_device &palette) const -{ - for (int i = 0; i < 4096; i++) - { - int const r = (i & 0x0f00) >> 8; - int const g = (i & 0x00f0) >> 4; - int const b = i & 0x000f; - palette.set_pen_color(i, r << 4, g << 4, b << 4); - } -} + PORT_START("SOUND_OUTPUT") + PORT_CONFNAME( 0x01, 0x01, "Sound output select" ) PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(wswan_state::sound_output_changed), 0) + PORT_CONFSETTING( 0x00, "Internal speaker (Mono)" ) + PORT_CONFSETTING( 0x01, "External headphone (Stereo)" ) +INPUT_PORTS_END static void wswan_cart(device_slot_interface &device) @@ -273,15 +296,13 @@ void wswan_state::wswan_base(machine_config &config) WSWAN_VIDEO(config, m_vdp, X1 / 4); m_vdp->set_screen("screen"); - 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)); m_vdp->icons_cb().set(FUNC(wswan_state::set_icons)); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); screen.set_screen_update("vdp", FUNC(wswan_video_device::screen_update)); screen.set_raw(X1 / 4, 256, 0, wswan_video_device::WSWAN_X_PIXELS, 159, 0, wswan_video_device::WSWAN_Y_PIXELS); - screen.set_palette("palette"); + screen.set_palette("vdp"); config.set_default_layout(layout_wswan); @@ -289,9 +310,6 @@ void wswan_state::wswan_base(machine_config &config) NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); - GFXDECODE(config, "gfxdecode", "palette", gfx_wswan); - PALETTE(config, "palette", FUNC(wswan_state::palette), 16); - // sound hardware SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); @@ -329,12 +347,13 @@ void wscolor_state::wscolor(machine_config &config) wswan(config); m_maincpu->set_addrmap(AS_PROGRAM, &wscolor_state::mem_map); + m_maincpu->set_addrmap(AS_IO, &wscolor_state::io_map); - 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::palette)); + WSWAN_COLOR_VIDEO(config.replace(), m_vdp, X1 / 4); + m_vdp->set_screen("screen"); + m_vdp->set_irq_callback(FUNC(wscolor_state::set_irq_line)); + m_vdp->icons_cb().set(FUNC(wscolor_state::set_icons)); + m_vdp->color_mode_cb().set(FUNC(wscolor_state::color_mode_view_w)); // software lists config.device_remove("wsc_list"); @@ -344,6 +363,10 @@ void wscolor_state::wscolor(machine_config &config) m_cart->set_must_be_loaded(true); } +INPUT_CHANGED_MEMBER(wswan_state::sound_output_changed) +{ + m_sound->set_headphone_connected(BIT(m_sound_output->read(), 0)); +} void wswan_state::handle_irqs() { @@ -402,19 +425,44 @@ void wswan_state::set_irq_line(int irq) } -void wswan_state::dma_sound_cb() +TIMER_CALLBACK_MEMBER(wscolor_state::sound_dma_cb) { - if ((m_sound_dma.enable & 0x88) == 0x80) + if (BIT(m_sound_dma.control, 7)) { - address_space &space = m_maincpu->space(AS_PROGRAM); - /* TODO: Output sound DMA byte */ - port_w(0x88 > 2, space.read_byte(m_sound_dma.source) << 8, 0xff00); - m_sound_dma.size--; - m_sound_dma.source = (m_sound_dma.source + 1) & 0x0fffff; - if (m_sound_dma.size == 0) + if (BIT(m_sound_dma.control, 2)) { - m_sound_dma.enable &= 0x7f; + // Sound DMA hold + if (BIT(m_sound_dma.control, 4)) + m_sound->hypervoice_dma_w(0); + else + port_w(0x88 / 2, 0 << 8, 0xff00); } + else + { + address_space &space = m_maincpu->space(AS_PROGRAM); + /* TODO: Output sound DMA byte */ + if (BIT(m_sound_dma.control, 4)) + m_sound->hypervoice_dma_w(space.read_byte(m_sound_dma.source)); + else + port_w(0x88 / 2, space.read_byte(m_sound_dma.source) << 8, 0xff00); + m_sound_dma.size--; + m_sound_dma.source = (m_sound_dma.source + (BIT(m_sound_dma.control, 6) ? -1 : 1)) & 0x0fffff; + if (m_sound_dma.size == 0) + { + if (BIT(m_sound_dma.control, 3)) + { + m_sound_dma.source = m_sound_dma.source_reload; + m_sound_dma.size = m_sound_dma.size_reload; + } + else + { + m_sound_dma.control &= 0x7f; + m_sound_dma.timer->adjust(attotime::never); + return; + } + } + } + m_sound_dma.timer->adjust(attotime::from_ticks(SOUND_DMA_DIV[m_sound_dma.control & 3], X1 / 512)); } } @@ -426,42 +474,10 @@ void wswan_state::clear_irq_line(int irq) } -void wswan_state::register_save() +void wswan_state::common_start() { - 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)); - save_item(NAME(m_vector)); - - save_item(NAME(m_dma_source_offset)); - save_item(NAME(m_dma_source_segment)); - save_item(NAME(m_dma_destination)); - save_item(NAME(m_dma_length)); - save_item(NAME(m_dma_control)); - save_item(NAME(m_sys_control)); - save_item(NAME(m_irq_vector_base)); - save_item(NAME(m_serial_data)); - save_item(NAME(m_serial_control)); - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_active)); - save_item(NAME(m_internal_eeprom_data)); - save_item(NAME(m_internal_eeprom_address)); - save_item(NAME(m_internal_eeprom_command)); - save_item(NAME(m_keypad)); - if (m_cart->exists()) m_cart->save_nvram(); -} - - -void wswan_state::common_start() -{ - register_save(); m_icons.resolve(); @@ -479,6 +495,24 @@ void wswan_state::common_start() m_maincpu->space(AS_PROGRAM).install_write_handler(0x10000, 0x1ffff, write16s_delegate(*m_cart, FUNC(ws_cart_slot_device::write_ram))); } } + + 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_vector)); + + save_item(NAME(m_sys_control)); + save_item(NAME(m_irq_vector_base)); + save_item(NAME(m_serial_data)); + save_item(NAME(m_serial_control)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_irq_active)); + save_item(NAME(m_internal_eeprom_data)); + save_item(NAME(m_internal_eeprom_address)); + save_item(NAME(m_internal_eeprom_command)); + save_item(NAME(m_keypad)); } @@ -495,12 +529,26 @@ 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; + + m_sound_dma.timer = timer_alloc(FUNC(wscolor_state::sound_dma_cb), this); + save_item(NAME(m_sound_dma.source)); + save_item(NAME(m_sound_dma.source_reload)); + save_item(NAME(m_sound_dma.size)); + save_item(NAME(m_sound_dma.size_reload)); + save_item(NAME(m_sound_dma.control)); + + save_item(NAME(m_dma_source_offset)); + save_item(NAME(m_dma_source_segment)); + save_item(NAME(m_dma_destination)); + save_item(NAME(m_dma_length)); + save_item(NAME(m_dma_control)); } void wswan_state::machine_reset() { - m_bios_disabled = 0; + m_sound->set_headphone_connected(BIT(m_sound_output->read(), 0)); + m_bios_disabled = false; m_rotate = 0; @@ -518,9 +566,35 @@ void wswan_state::machine_reset() std::fill(std::begin(m_ws_portram), std::end(m_ws_portram), 0); set_rotate_view(); +} + +void wscolor_state::machine_reset() +{ + wswan_state::machine_reset(); + + m_dma_view.disable(); + m_hypervoice_view.disable(); /* Initialize sound DMA */ - m_sound_dma = sound_dma_t(); + m_sound_dma.timer->adjust(attotime::never); + m_sound_dma.source = m_sound_dma.source_reload = 0; + m_sound_dma.size = m_sound_dma.size_reload = 0; + m_sound_dma.control = 0; +} + + +void wscolor_state::color_mode_view_w(int state) +{ + if (state) + { + m_dma_view.select(0); + m_hypervoice_view.select(0); + } + else + { + m_dma_view.disable(); + m_hypervoice_view.disable(); + } } @@ -548,34 +622,12 @@ u16 wswan_state::port_r(offs_t offset, u16 mem_mask) switch (offset) { - case 0x40 / 2: // DMA source address - return m_dma_source_offset; - case 0x42 / 2: // DMA source bank/segment - return m_dma_source_segment; - case 0x44 / 2: // DMA destination address - return m_dma_destination; - case 0x46 / 2: // DMA size (in bytes) - return m_dma_length; - case 0x48 / 2: // DMA control - return m_dma_control; - case 0x4a / 2: - // Sound DMA source address - return m_sound_dma.source & 0xffff; - case 0x4c / 2: - // Sound DMA source memory segment - return (m_sound_dma.source >> 16) & 0xffff; - case 0x4e / 2: - // Sound DMA transfer size - return m_sound_dma.size; - case 0x52 / 2: - // Sound DMA start/stop - return m_sound_dma.enable; case 0x60 / 2: return m_vdp->reg_r(offset, mem_mask); case 0xa0 / 2: // Hardware type // Bit 0 - Disable/enable BIOS - // Bit 1 - Determine mono/color + // Bit 1 - Determine monochrome/color // Bit 2 - Unknown, used to determine color/crystal // Bit 3 - Unknown // Bit 7 - Checked during start up, expects bit 7 set (part of cart unlock sequence?) @@ -597,13 +649,13 @@ u16 wswan_state::port_r(offs_t offset, u16 mem_mask) { case 0x10: // Read Y cursors: Y1 - Y2 - Y3 - Y4 { - u8 input = m_cursy->read(); + u8 const input = m_cursy->read(); if (m_rotate) // reorient controls if the console is rotated { - if (input & 0x01) value |= 0x0200; - if (input & 0x02) value |= 0x0400; - if (input & 0x04) value |= 0x0800; - if (input & 0x08) value |= 0x0100; + if (BIT(input, 0)) value |= 0x0200; + if (BIT(input, 1)) value |= 0x0400; + if (BIT(input, 2)) value |= 0x0800; + if (BIT(input, 3)) value |= 0x0100; } else value = value | (input << 8); @@ -611,13 +663,13 @@ u16 wswan_state::port_r(offs_t offset, u16 mem_mask) break; case 0x20: // Read X cursors: X1 - X2 - X3 - X4 { - u8 input = m_cursx->read(); + u8 const input = m_cursx->read(); if (m_rotate) // reorient controls if the console is rotated { - if (input & 0x01) value |= 0x0200; - if (input & 0x02) value |= 0x0400; - if (input & 0x04) value |= 0x0800; - if (input & 0x08) value |= 0x0100; + if (BIT(input, 0)) value |= 0x0200; + if (BIT(input, 1)) value |= 0x0400; + if (BIT(input, 2)) value |= 0x0800; + if (BIT(input, 3)) value |= 0x0100; } else value = value | (input << 8); @@ -645,6 +697,10 @@ u16 wswan_state::port_r(offs_t offset, u16 mem_mask) case 0xcc / 2: case 0xce / 2: return m_cart->read_io(offset, mem_mask); + default: + if (!machine().side_effects_disabled()) + LOGUNKNOWN("%s: Read from unsupported port: %02x & %04x", machine().describe_context(), offset << 1, mem_mask); + break; } return value; @@ -661,75 +717,6 @@ void wswan_state::port_w(offs_t offset, u16 data, u16 mem_mask) switch (offset) { - case 0x40 / 2: // DMA source address - COMBINE_DATA(&m_dma_source_offset); - m_dma_source_offset &= 0xfffe; - break; - case 0x42 / 2: // DMA source bank/segment - COMBINE_DATA(&m_dma_source_segment); - m_dma_source_segment &= 0x000f; - break; - case 0x44 / 2: // DMA destination address - COMBINE_DATA(&m_dma_destination); - m_dma_destination &= 0xfffe; - break; - case 0x46 / 2: // DMA size (in bytes) - COMBINE_DATA(&m_dma_length); - break; - case 0x48 / 2: // DMA control - // Bit 0-6 - Unknown - // Bit 7 - DMA stop/start - if (ACCESSING_BITS_0_7) - { - if (data & 0x80) - { - address_space &mem = m_maincpu->space(AS_PROGRAM); - u32 src = m_dma_source_offset | (m_dma_source_segment << 16); - u32 dst = m_dma_destination; - u16 length = m_dma_length; - if (length) - m_maincpu->adjust_icount(-(5 + length)); - for ( ; length > 0; length -= 2) - { - mem.write_word(dst, mem.read_word(src)); - src += 2; - dst += 2; - } - m_dma_source_offset = src & 0xffff; - m_dma_source_segment = src >> 16; - m_dma_destination = dst & 0xffff; - m_dma_length = length & 0xffff; - data &= 0x7f; - m_dma_control = data; - } - } - break; - case 0x4a / 2: - // Sound DMA source address (low) - if (ACCESSING_BITS_0_7) - m_sound_dma.source = (m_sound_dma.source & 0x0fff00) | (data & 0xff); - // Sound DMA source address (high) - if (ACCESSING_BITS_8_15) - m_sound_dma.source = (m_sound_dma.source & 0x0f00ff) | (data & 0xff00); - break; - case 0x4c / 2: - // Sound DMA source memory segment - // Bit 0-3 - Sound DMA source address segment - // Bit 4-7 - Unknown - if (ACCESSING_BITS_0_7) - m_sound_dma.source = (m_sound_dma.source & 0xffff) | ((data & 0x0f) << 16); - break; - case 0x4e / 2: - // Sound DMA transfer size - COMBINE_DATA(&m_sound_dma.size); - break; - case 0x52 / 2: - // Sound DMA start/stop - // Bit 0-6 - Unknown - // Bit 7 - Sound DMA stop/start - if (ACCESSING_BITS_0_7) - m_sound_dma.enable = data & 0xff; - break; case 0x60 / 2: m_vdp->reg_w(offset, data, mem_mask); break; @@ -795,9 +782,9 @@ void wswan_state::port_w(offs_t offset, u16 data, u16 mem_mask) if (ACCESSING_BITS_0_7) { m_sys_control = (data & 0xfd) | ((m_system_type == TYPE_WSC) ? 2 : 0); - if ((data & 0x01) && !m_bios_disabled) + if (BIT(data, 0) && !m_bios_disabled) { - m_bios_disabled = 1; + m_bios_disabled = true; if (m_cart->exists()) m_maincpu->space(AS_PROGRAM).install_read_handler(0x40000, 0xfffff, read16s_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom40))); } @@ -836,12 +823,12 @@ void wswan_state::port_w(offs_t offset, u16 data, u16 mem_mask) { m_serial_data = 0xff; m_serial_control = data >> 8; - if (m_serial_control & 0x80) + if (BIT(m_serial_control, 7)) { // m_serial_data = 0x00; m_serial_control |= 0x04; } - if (m_serial_control & 0x20) + if (BIT(m_serial_control, 5)) { // m_serial_control |= 0x01; } @@ -890,22 +877,22 @@ void wswan_state::port_w(offs_t offset, u16 data, u16 mem_mask) if (ACCESSING_BITS_0_7) { m_internal_eeprom_command = data & 0xfc; - if (m_internal_eeprom_command & 0x20) + if (BIT(m_internal_eeprom_command, 5)) { - u16 addr = get_internal_eeprom_address(); + u16 const addr = get_internal_eeprom_address(); m_internal_eeprom[addr] = m_internal_eeprom_data & 0xff; m_internal_eeprom[addr + 1] = m_internal_eeprom_data >> 8; m_internal_eeprom_command |= 0x02; } - else if (m_internal_eeprom_command & 0x10) + else if (BIT(m_internal_eeprom_command, 4)) { - u16 addr = get_internal_eeprom_address(); + u16 const addr = get_internal_eeprom_address(); m_internal_eeprom_data = m_internal_eeprom[addr] | (m_internal_eeprom[addr + 1] << 8); m_internal_eeprom_command |= 0x01; } else { - logerror("Unsupported internal EEPROM command: %X\n", data); + LOGEEPROM("%s: Unsupported internal EEPROM command: %02X\n", machine().describe_context(), data & 0xff); } } break; @@ -920,10 +907,175 @@ void wswan_state::port_w(offs_t offset, u16 data, u16 mem_mask) m_cart->write_io(offset, data, mem_mask); break; default: - logerror("Write to unsupported port: %x - %x\n", offset, data); + LOGUNKNOWN("%s: Write to unsupported port: %02x - %04x & %04x\n", machine().describe_context(), offset << 1, data, mem_mask); + break; + } + + // Update the port value + COMBINE_DATA(&m_ws_portram[offset]); +} + + +u16 wscolor_state::dma_r(offs_t offset, u16 mem_mask) +{ + offset += 0x40 / 2; + u16 const value = m_ws_portram[offset]; + + switch (offset) + { + case 0x40 / 2: // DMA source address + return m_dma_source_offset; + case 0x42 / 2: // DMA source bank/segment + return m_dma_source_segment; + case 0x44 / 2: // DMA destination address + return m_dma_destination; + case 0x46 / 2: // DMA size (in bytes) + return m_dma_length; + case 0x48 / 2: // DMA control + return m_dma_control; + case 0x4a / 2: + // Sound DMA source address + return m_sound_dma.source & 0xffff; + case 0x4c / 2: + // Sound DMA source memory segment + return (m_sound_dma.source >> 16) & 0xffff; + case 0x4e / 2: + // Sound DMA transfer size (low 16 bits) + return m_sound_dma.size & 0xffff; + case 0x50 / 2: + // Sound DMA transfer size (high 4 bits) + return (m_sound_dma.size >> 16) & 0xffff; + case 0x52 / 2: + // Sound DMA control + return m_sound_dma.control; + default: + if (!machine().side_effects_disabled()) + LOGDMA("%s: Read from unknown DMA port: %02x & %04x", machine().describe_context(), offset << 1, mem_mask); break; } + return value; +} + +void wscolor_state::dma_w(offs_t offset, u16 data, u16 mem_mask) +{ + offset += 0x40 / 2; + switch (offset) + { + case 0x40 / 2: // DMA source address + COMBINE_DATA(&m_dma_source_offset); + m_dma_source_offset &= 0xfffe; + break; + case 0x42 / 2: // DMA source bank/segment + COMBINE_DATA(&m_dma_source_segment); + m_dma_source_segment &= 0x000f; + break; + case 0x44 / 2: // DMA destination address + COMBINE_DATA(&m_dma_destination); + m_dma_destination &= 0xfffe; + break; + case 0x46 / 2: // DMA size (in bytes) + COMBINE_DATA(&m_dma_length); + break; + case 0x48 / 2: // DMA control + // Bit 0-6 - Unknown + // Bit 7 - DMA stop/start + if (ACCESSING_BITS_0_7) + { + if (BIT(data, 7)) + { + address_space &mem = m_maincpu->space(AS_PROGRAM); + u32 src = m_dma_source_offset | (m_dma_source_segment << 16); + u32 dst = m_dma_destination; + u16 length = m_dma_length; + s32 const inc = BIT(data, 6) ? -2 : 2; + if (length) + m_maincpu->adjust_icount(-(5 + length)); + for ( ; length > 0; length -= 2) + { + mem.write_word(dst, mem.read_word(src)); + src += inc; + dst += inc; + } + m_dma_source_offset = src & 0xffff; + m_dma_source_segment = src >> 16; + m_dma_destination = dst & 0xffff; + m_dma_length = length & 0xffff; + data &= 0x7f; + m_dma_control = data; + } + } + break; + case 0x4a / 2: + // Sound DMA source address (low) + if (ACCESSING_BITS_0_7) + { + m_sound_dma.source = (m_sound_dma.source & 0x0fff00) | (data & 0xff); + m_sound_dma.source_reload = (m_sound_dma.source_reload & 0x0fff00) | (data & 0xff); + } + // Sound DMA source address (high) + if (ACCESSING_BITS_8_15) + { + m_sound_dma.source = (m_sound_dma.source & 0x0f00ff) | (data & 0xff00); + m_sound_dma.source_reload = (m_sound_dma.source_reload & 0x0f00ff) | (data & 0xff00); + } + break; + case 0x4c / 2: + // Sound DMA source memory segment + // Bit 0-3 - Sound DMA source address segment + // Bit 4-7 - Unknown + if (ACCESSING_BITS_0_7) + { + m_sound_dma.source = (m_sound_dma.source & 0xffff) | ((data & 0x0f) << 16); + m_sound_dma.source_reload = (m_sound_dma.source_reload & 0xffff) | ((data & 0x0f) << 16); + } + break; + case 0x4e / 2: + // Sound DMA transfer size + // Sound DMA transfer size (bit 0-7) + if (ACCESSING_BITS_0_7) + { + m_sound_dma.size = (m_sound_dma.size & 0x0fff00) | (data & 0xff); + m_sound_dma.size_reload = (m_sound_dma.size_reload & 0x0fff00) | (data & 0xff); + } + // Sound DMA transfer size (bit 8-15) + if (ACCESSING_BITS_8_15) + { + m_sound_dma.size = (m_sound_dma.size & 0x0f00ff) | (data & 0xff00); + m_sound_dma.size_reload = (m_sound_dma.size_reload & 0x0f00ff) | (data & 0xff00); + } + break; + case 0x50 / 2: + // Sound DMA transfer size (high 4 bits) + // Bit 0-3 - Sound DMA transfer size (high 4 bits) + // Bit 4-7 - Unknown + if (ACCESSING_BITS_0_7) + { + m_sound_dma.size = (m_sound_dma.size & 0xffff) | ((data & 0x0f) << 16); + m_sound_dma.size_reload = (m_sound_dma.size_reload & 0xffff) | ((data & 0x0f) << 16); + } + break; + case 0x52 / 2: + // Sound DMA control + // Bit 0-1 - Sound DMA frequency (4000hz, 6000hz, 12000hz, 24000hz) + // Bit 2 - Sound DMA hold mode (0 = normal playback, 1 = hold) + // Bit 3 - Sound DMA repeat mode (0 = one-shot, 1 = auto-repeat) + // Bit 4 - Sound DMA target (0 = channel 2, 1 = hyper voice) + // Bit 6 - Sound DMA direction (0 = increment, 1 = decrement) + // Bit 7 - Sound DMA stop/start + if (ACCESSING_BITS_0_7) + { + m_sound_dma.control = data & 0xff; + if (BIT(m_sound_dma.control, 7)) + m_sound_dma.timer->adjust(attotime::from_ticks(SOUND_DMA_DIV[m_sound_dma.control & 3], X1 / 512)); + else + m_sound_dma.timer->adjust(attotime::never); + } + break; + default: + LOGDMA("%s: Write to unknown DMA port: %x - %x\n", machine().describe_context(), offset, data); + break; + } // Update the port value COMBINE_DATA(&m_ws_portram[offset]); } @@ -942,7 +1094,7 @@ void wswan_state::set_icons(u8 data) m_icons[i] = BIT(data, i); } - u8 old_rotate = m_rotate; + u8 const old_rotate = m_rotate; if ((!BIT(data, 2) && BIT(data, 1)) || (BIT(data, 2) && !BIT(data, 1))) { @@ -950,7 +1102,7 @@ void wswan_state::set_icons(u8 data) if (old_rotate != m_rotate) { - set_rotate_view(); + set_rotate_view(); } } } diff --git a/src/mame/bandai/wswan_v.cpp b/src/mame/bandai/wswan_v.cpp index 469f6c74a0e..5a7abf2a6a9 100644 --- a/src/mame/bandai/wswan_v.cpp +++ b/src/mame/bandai/wswan_v.cpp @@ -8,7 +8,6 @@ Wilbert Pol TODO: - - split the Color VDP from the Mono VDP - Add support for WSC high/low contrast (register 14, bit 1) ***************************************************************************/ @@ -17,16 +16,40 @@ #include "wswan_v.h" #include "screen.h" -DEFINE_DEVICE_TYPE(WSWAN_VIDEO, wswan_video_device, "wswan_video", "Bandai WonderSwam VDP") +#define LOG_UNKNOWN (1 << 1) +#define LOG_SCANLINE (1 << 2) +#define LOG_ALL (LOG_UNKNOWN | LOG_SCANLINE) -wswan_video_device::wswan_video_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : device_t(mconfig, WSWAN_VIDEO, tag, owner, clock) +#define VERBOSE (0) + +#include "logmacro.h" + +#define LOGUNKNOWN(...) LOGMASKED(LOG_UNKNOWN, __VA_ARGS__) +#define LOGSCANLINE(...) LOGMASKED(LOG_SCANLINE, __VA_ARGS__) + +DEFINE_DEVICE_TYPE(WSWAN_VIDEO, wswan_video_device, "wswan_video", "Bandai WonderSwan VDP") +DEFINE_DEVICE_TYPE(WSWAN_COLOR_VIDEO, wswan_color_video_device, "wscolor_video", "Bandai WonderSwan Color VDP") + + +wswan_video_device::wswan_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int vdp_type) + : device_t(mconfig, type, tag, owner, clock) , device_video_interface(mconfig, *this) + , device_palette_interface(mconfig, *this) , m_set_irq_cb(*this) - , m_snd_dma_cb(*this) - , m_vdp_type(VDP_TYPE_WSWAN) + , m_vdp_type(vdp_type) , m_icons_cb(*this) + , m_color_mode_cb(*this) +{ +} + +wswan_video_device::wswan_video_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : wswan_video_device(mconfig, WSWAN_VIDEO, tag, owner, clock, VDP_TYPE_WSWAN) +{ +} + +wswan_color_video_device::wswan_color_video_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : wswan_video_device(mconfig, WSWAN_COLOR_VIDEO, tag, owner, clock, VDP_TYPE_WSC) { } @@ -35,12 +58,23 @@ wswan_video_device::~wswan_video_device() } -void wswan_video_device::common_save() +void wswan_video_device::device_start() { + init_palettes(); + screen().register_screen_bitmap(m_bitmap); + + m_timer = timer_alloc(FUNC(wswan_video_device::scanline_interrupt), this); + m_timer->adjust(attotime::from_ticks(256, clock()), 0, attotime::from_ticks(256, clock())); + + // bind callbacks + m_set_irq_cb.resolve(); + + const size_t vram_size = (is_color_vdp() ? 0x10000 : 0x4000) >> 1; + m_vram = make_unique_clear<u16 []>(vram_size); + save_item(NAME(m_bitmap)); - save_item(NAME(m_vram)); + save_pointer(NAME(m_vram), vram_size); save_item(NAME(m_palette_port)); - save_item(NAME(m_pal)); save_item(NAME(m_regs)); save_item(NAME(m_layer_bg_enable)); @@ -83,43 +117,14 @@ void wswan_video_device::common_save() save_item(NAME(m_timer_vblank_mode)); save_item(NAME(m_timer_vblank_reload)); save_item(NAME(m_timer_vblank_count)); - save_item(NAME(m_main_palette)); -} - -void wswan_video_device::device_start() -{ - screen().register_screen_bitmap(m_bitmap); - - m_timer = timer_alloc(FUNC(wswan_video_device::scanline_interrupt), this); - m_timer->adjust(attotime::from_ticks(256, clock()), 0, attotime::from_ticks(256, clock())); - - // bind callbacks - m_set_irq_cb.resolve(); - m_snd_dma_cb.resolve(); - - if (m_vdp_type == VDP_TYPE_WSC) - { - m_vram.resize(WSC_VRAM_SIZE); - m_palette_vram = &m_vram[WSC_VRAM_PALETTE]; - } - else - { - m_vram.resize(WS_VRAM_SIZE); - m_palette_vram = &m_vram[0]; - } - - std::fill(std::begin(m_vram), std::end(m_vram), 0); - - common_save(); } - void wswan_video_device::device_reset() { - m_layer_bg_enable = 0; - m_layer_fg_enable = 0; - m_sprites_enable = 0; - m_window_sprites_enable = 0; + m_layer_bg_enable = false; + m_layer_fg_enable = false; + m_sprites_enable = false; + m_window_sprites_enable = false; m_window_fg_mode = 0; m_bg_control = 0; m_current_line = 0; @@ -144,145 +149,192 @@ void wswan_video_device::device_reset() m_layer_fg_scroll_x = 0; m_layer_fg_scroll_y = 0; m_lcd_control = 0; - m_color_mode = 0; - m_colors_16 = 0; - m_tile_packed = 0; - m_timer_hblank_enable = 0; - m_timer_hblank_mode = 0; + m_color_mode = false; + m_colors_16 = false; + m_tile_packed = false; + m_timer_hblank_enable = false; + m_timer_hblank_mode = false; m_timer_hblank_reload = 0; m_timer_hblank_count = 0; - m_timer_vblank_enable = 0; - m_timer_vblank_mode = 0; + m_timer_vblank_enable = false; + m_timer_vblank_mode = false; m_timer_vblank_reload = 0; m_timer_vblank_count = 0; std::fill(std::begin(m_sprite_table_buffer), std::end(m_sprite_table_buffer), 0); - std::fill(std::begin(m_main_palette), std::end(m_main_palette), 0); std::fill(std::begin(m_regs), std::end(m_regs), 0); std::fill(std::begin(m_palette_port), std::end(m_palette_port), 0); setup_palettes(); } +void wswan_video_device::init_palettes() +{ + for (int i = 0; i < 8; i++) + { + set_indirect_color(i, rgb_t::white()); + } + if (is_color_vdp()) + { + for (int i = 0; i < 4096; i++) + { + u16 const r = (i & 0x0f00) >> 8; + u16 const g = (i & 0x00f0) >> 4; + u16 const b = i & 0x000f; + set_indirect_color(COLOR_12BIT + i, rgb_t(pal4bit(r), pal4bit(g), pal4bit(b))); + } + set_pen_indirect(256, COLOR_12BIT + 0xfff); // background color for monochrome mode if LCD off + set_pen_indirect(256 + 1, COLOR_12BIT); // background color for color mode if LCD off + } + else + { + // background color if LCD off + set_indirect_color(8, rgb_t::white()); + set_pen_indirect(BG_COLOR + 1, 8); + } +} void wswan_video_device::setup_palettes() { - if (m_color_mode) + if (is_color_vdp() && m_color_mode) { - for (int i = 0; i < 16; i++) - for (int j = 0; j < 16; j++) - m_pal[i][j] = m_palette_vram[(i << 4) + j] & 0x0fff; + for (int i = 0; i < 256; i++) + set_pen_indirect(i, COLOR_12BIT + (m_vram[WSC_VRAM_PALETTE + i] & 0x0fff)); } else { - for (int i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) { - m_pal[i][0] = (m_palette_port[i] >> 0) & 0x07; - m_pal[i][1] = (m_palette_port[i] >> 4) & 0x07; - m_pal[i][2] = (m_palette_port[i] >> 8) & 0x07; - m_pal[i][3] = (m_palette_port[i] >> 12) & 0x07; + set_pen_indirect((i << 2) + 0, (m_palette_port[i] >> 0) & 0x07); + set_pen_indirect((i << 2) + 1, (m_palette_port[i] >> 4) & 0x07); + set_pen_indirect((i << 2) + 2, (m_palette_port[i] >> 8) & 0x07); + set_pen_indirect((i << 2) + 3, (m_palette_port[i] >> 12) & 0x07); } + set_pen_indirect(BG_COLOR, m_bg_control & 0x07); } } - -void wswan_video_device::draw_background() +inline void wswan_video_device::get_tile_data(u16 map_addr, u8 scrolly, u16 &data, u16 &number, u16 &palette, int &line) { - const u16 map_addr = m_layer_bg_address + (((m_current_line + m_layer_bg_scroll_y) & 0xf8) << 2); - const u8 start_column = (m_layer_bg_scroll_x >> 3); + data = m_vram[map_addr]; + number = data & 0x01ff; + palette = (data >> 9) & 0x0f; - for (int column = 0; column < 29; column++) - { - u32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0; - int x_offset, tile_line; - const u16 tile_data = m_vram[map_addr + ((start_column + column) & 0x1f)]; - const u16 tile_number = tile_data & 0x01ff; - const u16 tile_palette = (tile_data >> 9) & 0x0f; + line = (m_current_line + scrolly) & 0x07; + if (BIT(data, 15)) // vflip + line = 7 - line; +} - tile_line = (m_current_line + m_layer_bg_scroll_y) & 0x07; - if (tile_data & 0x8000) // vflip - tile_line = 7 - tile_line; +inline void wswan_video_device::get_planes(bool bank, u32 number, int line, u32 &plane0, u32 &plane1, u32 &plane2, u32 &plane3) +{ + if (m_colors_16) + { + const u16 tile_address = (bank ? 0x4000 : 0x2000) + (number * 16) + (line << 1); + if (m_tile_packed) + { + plane0 = (swapendian_int16(m_vram[tile_address]) << 16) | swapendian_int16(m_vram[tile_address + 1]); + } + else + { + plane0 = m_vram[tile_address] & 0xff; + plane1 = (m_vram[tile_address] & 0xff00) >> 7; + plane2 = (m_vram[tile_address + 1] & 0xff) << 2; + plane3 = (m_vram[tile_address + 1] & 0xff00) >> 5; + } + } + else + { + const u16 tile_address = ((m_color_mode && bank) ? 0x2000 : 0x1000) + (number * 8) + line; + if (m_tile_packed) + { + plane0 = m_vram[tile_address]; + } + else + { + plane0 = m_vram[tile_address] & 0xff; + plane1 = (m_vram[tile_address] & 0xff00) >> 7; + plane2 = 0; + plane3 = 0; + } + } +} +inline u8 wswan_video_device::extract_planes(u32 &plane0, u32 &plane1, u32 &plane2, u32 &plane3) +{ + u8 col; + if (m_tile_packed) + { if (m_colors_16) { - const u16 tile_address = ((tile_data & 0x2000) ? 0x4000 : 0x2000) + (tile_number * 16) + (tile_line << 1); - if (m_tile_packed) - { - plane0 = (swapendian_int16(m_vram[tile_address]) << 16) | swapendian_int16(m_vram[tile_address + 1]); - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = (m_vram[tile_address + 1] & 0xff) << 2; - plane3 = (m_vram[tile_address + 1] & 0xff00) >> 5; - } + col = plane0 & 0x0f; + plane0 >>= 4; } else { - const u16 tile_address = 0x1000 + (tile_number * 8) + tile_line; - if (m_tile_packed) - { - plane0 = m_vram[tile_address]; - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = 0; - plane3 = 0; - } + col = plane0 & 0x03; + plane0 >>= 2; } + } + else + { + col = (plane3 & 8) | (plane2 & 4) | (plane1 & 2) | (plane0 & 1); + plane3 >>= 1; + plane2 >>= 1; + plane1 >>= 1; + plane0 >>= 1; + } + return col; +} - for (int x = 0; x < 8; x++) +inline int wswan_video_device::get_xoffset(bool hflip, int x, int column, u8 scrollx) +{ + if (hflip) + return x + (column << 3) - (scrollx & 0x07); + else + return 7 - x + (column << 3) - (scrollx & 0x07); +} + +inline void wswan_video_device::draw_pixel(int x_offset, u8 tile_palette, u8 pixel) +{ + if (m_colors_16) + { + if (pixel) { - int col; - if (m_tile_packed) - { - if (m_colors_16) - { - col = plane0 & 0x0f; - plane0 = plane0 >> 4; - } - else - { - col = plane0 & 0x03; - plane0 = plane0 >> 2; - } - } + m_bitmap.pix(m_current_line, x_offset) = (tile_palette << 4) | pixel; + } + } + else + { + if (pixel || BIT(~tile_palette, 2)) + { + if (m_color_mode) + m_bitmap.pix(m_current_line, x_offset) = (tile_palette << 4) | pixel; else - { - col = (plane3 & 8) | (plane2 & 4) | (plane1 & 2) | (plane0 & 1); - plane3 = plane3 >> 1; - plane2 = plane2 >> 1; - plane1 = plane1 >> 1; - plane0 = plane0 >> 1; - } + m_bitmap.pix(m_current_line, x_offset) = (tile_palette << 2) | pixel; + } + } +} - if (tile_data & 0x4000) - x_offset = x + (column << 3) - (m_layer_bg_scroll_x & 0x07); - else - x_offset = 7 - x + (column << 3) - (m_layer_bg_scroll_x & 0x07); +void wswan_video_device::draw_background() +{ + const u16 map_addr = (m_layer_bg_address & (m_color_mode ? 0x3fff : 0x1fff)) + (((m_current_line + m_layer_bg_scroll_y) & 0xf8) << 2); + const u8 start_column = (m_layer_bg_scroll_x >> 3); + + for (int column = 0; column < 29; column++) + { + u32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0; + u16 tile_data, tile_number, tile_palette; + int tile_line; + get_tile_data(map_addr + ((start_column + column) & 0x1f), m_layer_bg_scroll_y, tile_data, tile_number, tile_palette, tile_line); + get_planes(BIT(tile_data, 13), tile_number, tile_line, plane0, plane1, plane2, plane3); + for (int x = 0; x < 8; x++) + { + const u8 col = extract_planes(plane0, plane1, plane2, plane3); + const int x_offset = get_xoffset(BIT(tile_data, 14), x, column, m_layer_bg_scroll_x); if (x_offset >= 0 && x_offset < WSWAN_X_PIXELS) { - if (m_colors_16) - { - if (col) - { - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - } - } - else - { - if (col || !(tile_palette & 4)) - { - if (m_color_mode) - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - else - m_bitmap.pix(m_current_line, x_offset) = m_main_palette[m_pal[tile_palette][col]]; - } - } + draw_pixel(x_offset, tile_palette, col); } } } @@ -290,101 +342,24 @@ void wswan_video_device::draw_background() void wswan_video_device::draw_foreground_0() { - const u16 map_addr = m_layer_fg_address + (((m_current_line + m_layer_fg_scroll_y) & 0xf8) << 2); + const u16 map_addr = (m_layer_fg_address & (m_color_mode ? 0x3fff : 0x1fff)) + (((m_current_line + m_layer_fg_scroll_y) & 0xf8) << 2); const u8 start_column = (m_layer_fg_scroll_x >> 3); for (int column = 0; column < 29; column++) { u32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0; - int x_offset, tile_line; - const u16 tile_data = m_vram[map_addr + ((start_column + column) & 0x1f)]; - const u16 tile_number = tile_data & 0x01ff; - const u16 tile_palette = (tile_data >> 9) & 0x0f; - - tile_line = (m_current_line + m_layer_fg_scroll_y) & 0x07; - if (tile_data & 0x8000) // vflip - tile_line = 7 - tile_line; - - if (m_colors_16) - { - const u16 tile_address = ((tile_data & 0x2000) ? 0x4000 : 0x2000) + (tile_number * 16) + (tile_line << 1); - if (m_tile_packed) - { - plane0 = (swapendian_int16(m_vram[tile_address]) << 16) | swapendian_int16(m_vram[tile_address + 1]); - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = (m_vram[tile_address + 1] & 0xff) << 2; - plane3 = (m_vram[tile_address + 1] & 0xff00) >> 5; - } - } - else - { - const u16 tile_address = 0x1000 + (tile_number * 8) + tile_line; - if (m_tile_packed) - { - plane0 = m_vram[tile_address]; - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = 0; - plane3 = 0; - } - } + u16 tile_data, tile_number, tile_palette; + int tile_line; + get_tile_data(map_addr + ((start_column + column) & 0x1f), m_layer_fg_scroll_y, tile_data, tile_number, tile_palette, tile_line); + get_planes(BIT(tile_data, 13), tile_number, tile_line, plane0, plane1, plane2, plane3); - for (int x = 0; x < 8; x++ ) + for (int x = 0; x < 8; x++) { - int col; - if (m_tile_packed) - { - if (m_colors_16) - { - col = plane0 & 0x0f; - plane0 = plane0 >> 4; - } - else - { - col = plane0 & 0x03; - plane0 = plane0 >> 2; - } - } - else - { - col = (plane3 & 8) | (plane2 & 4) | (plane1 & 2) | (plane0 & 1); - plane3 = plane3 >> 1; - plane2 = plane2 >> 1; - plane1 = plane1 >> 1; - plane0 = plane0 >> 1; - } - - if (tile_data & 0x4000) - x_offset = x + (column << 3) - (m_layer_fg_scroll_x & 0x07); - else - x_offset = 7 - x + (column << 3) - (m_layer_fg_scroll_x & 0x07); - + const u8 col = extract_planes(plane0, plane1, plane2, plane3); + const int x_offset = get_xoffset(BIT(tile_data, 14), x, column, m_layer_fg_scroll_x); if (x_offset >= 0 && x_offset < WSWAN_X_PIXELS) { - if (m_colors_16) - { - if (col) - { - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - } - } - else - { - if (col || !(tile_palette & 4)) - { - if (m_color_mode) - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - else - m_bitmap.pix(m_current_line, x_offset) = m_main_palette[m_pal[tile_palette][col]]; - } - } + draw_pixel(x_offset, tile_palette, col); } } } @@ -392,102 +367,24 @@ void wswan_video_device::draw_foreground_0() void wswan_video_device::draw_foreground_2() { - const u16 map_addr = m_layer_fg_address + (((m_current_line + m_layer_fg_scroll_y) & 0xf8) << 2); + const u16 map_addr = (m_layer_fg_address & (m_color_mode ? 0x3fff : 0x1fff)) + (((m_current_line + m_layer_fg_scroll_y) & 0xf8) << 2); const u8 start_column = (m_layer_fg_scroll_x >> 3); for (int column = 0; column < 29; column++) { u32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0; - int x_offset, tile_line; - const u16 tile_data = m_vram[map_addr + ((start_column + column) & 0x1f)]; - const u16 tile_number = tile_data & 0x01ff; - const u16 tile_palette = (tile_data >> 9) & 0x0f; - - tile_line = (m_current_line + m_layer_fg_scroll_y) & 0x07; - if (tile_data & 0x8000) // vflip - tile_line = 7 - tile_line; - - - if (m_colors_16) - { - const u16 tile_address = ((tile_data & 0x2000) ? 0x4000 : 0x2000) + (tile_number * 16) + (tile_line << 1); - if (m_tile_packed) - { - plane0 = (swapendian_int16(m_vram[tile_address]) << 16) | swapendian_int16(m_vram[tile_address + 1]); - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = (m_vram[tile_address + 1] & 0xff) << 2; - plane3 = (m_vram[tile_address + 1] & 0xff00) >> 5; - } - } - else - { - const u16 tile_address = 0x1000 + (tile_number * 8) + tile_line; - if (m_tile_packed) - { - plane0 = m_vram[tile_address]; - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = 0; - plane3 = 0; - } - } + u16 tile_data, tile_number, tile_palette; + int tile_line; + get_tile_data(map_addr + ((start_column + column) & 0x1f), m_layer_fg_scroll_y, tile_data, tile_number, tile_palette, tile_line); + get_planes(BIT(tile_data, 13), tile_number, tile_line, plane0, plane1, plane2, plane3); for (int x = 0; x < 8; x++) { - int col; - if (m_tile_packed) - { - if (m_colors_16) - { - col = plane0 & 0x0f; - plane0 = plane0 >> 4; - } - else - { - col = plane0 & 0x03; - plane0 = plane0 >> 2; - } - } - else - { - col = (plane3 & 8) | (plane2 & 4) | (plane1 & 2) | (plane0 & 1); - plane3 = plane3 >> 1; - plane2 = plane2 >> 1; - plane1 = plane1 >> 1; - plane0 = plane0 >> 1; - } - - if (tile_data & 0x4000) - x_offset = x + (column << 3) - (m_layer_fg_scroll_x & 0x07); - else - x_offset = 7 - x + (column << 3) - (m_layer_fg_scroll_x & 0x07); - + const u8 col = extract_planes(plane0, plane1, plane2, plane3); + const int x_offset = get_xoffset(BIT(tile_data, 14), x, column, m_layer_fg_scroll_x); if (x_offset >= 0 && x_offset >= m_window_fg_left && x_offset <= m_window_fg_right && x_offset < WSWAN_X_PIXELS) { - if (m_colors_16) - { - if (col) - { - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - } - } - else - { - if (col || !(tile_palette & 4)) - { - if (m_color_mode) - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - else - m_bitmap.pix(m_current_line, x_offset) = m_main_palette[m_pal[tile_palette][col]]; - } - } + draw_pixel(x_offset, tile_palette, col); } } } @@ -495,107 +392,30 @@ void wswan_video_device::draw_foreground_2() void wswan_video_device::draw_foreground_3() { - const u16 map_addr = m_layer_fg_address + (((m_current_line + m_layer_fg_scroll_y) & 0xf8) << 2); + const u16 map_addr = (m_layer_fg_address & (m_color_mode ? 0x3fff : 0x1fff)) + (((m_current_line + m_layer_fg_scroll_y) & 0xf8) << 2); const u8 start_column = (m_layer_fg_scroll_x >> 3); for (int column = 0; column < 29; column++) { u32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0; - int x_offset, tile_line; - const u16 tile_data = m_vram[map_addr + ((start_column + column) & 0x1f)]; - const u16 tile_number = tile_data & 0x01ff; - const u16 tile_palette = (tile_data >> 9) & 0x0f; - - tile_line = (m_current_line + m_layer_fg_scroll_y) & 0x07; - if (tile_data & 0x8000) // vflip - tile_line = 7 - tile_line; - - if (m_colors_16) - { - const u16 tile_address = ((tile_data & 0x2000) ? 0x4000 : 0x2000) + (tile_number * 16) + (tile_line << 1); - if (m_tile_packed) - { - plane0 = (swapendian_int16(m_vram[tile_address]) << 16) | swapendian_int16(m_vram[tile_address + 1]); - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = (m_vram[tile_address + 1] & 0xff) << 2; - plane3 = (m_vram[tile_address + 1] & 0xff00) >> 5; - } - } - else - { - const u16 tile_address = 0x1000 + (tile_number * 8) + tile_line; - if (m_tile_packed) - { - plane0 = m_vram[tile_address]; - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = 0; - plane3 = 0; - } - } + u16 tile_data, tile_number, tile_palette; + int tile_line; + get_tile_data(map_addr + ((start_column + column) & 0x1f), m_layer_fg_scroll_y, tile_data, tile_number, tile_palette, tile_line); + get_planes(BIT(tile_data, 13), tile_number, tile_line, plane0, plane1, plane2, plane3); for (int x = 0; x < 8; x++) { - int col; - if (m_tile_packed) - { - if (m_colors_16) - { - col = plane0 & 0x0f; - plane0 = plane0 >> 4; - } - else - { - col = plane0 & 0x03; - plane0 = plane0 >> 2; - } - } - else - { - col = (plane3 & 8) | (plane2 & 4) | (plane1 & 2) | (plane0 & 1); - plane3 = plane3 >> 1; - plane2 = plane2 >> 1; - plane1 = plane1 >> 1; - plane0 = plane0 >> 1; - } - - if (tile_data & 0x4000) - x_offset = x + (column << 3) - (m_layer_fg_scroll_x & 0x07); - else - x_offset = 7 - x + (column << 3) - (m_layer_fg_scroll_x & 0x07); - + const u8 col = extract_planes(plane0, plane1, plane2, plane3); + const int x_offset = get_xoffset(BIT(tile_data, 14), x, column, m_layer_fg_scroll_x); if ((x_offset >= 0 && x_offset < m_window_fg_left) || (x_offset > m_window_fg_right && x_offset < WSWAN_X_PIXELS)) { - if (m_colors_16) - { - if (col) - { - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - } - } - else - { - if (col || !(tile_palette & 4)) - { - if (m_color_mode) - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - else - m_bitmap.pix(m_current_line, x_offset) = m_main_palette[m_pal[tile_palette][col]]; - } - } + draw_pixel(x_offset, tile_palette, col); } } } } -void wswan_video_device::handle_sprites(int mask) +void wswan_video_device::handle_sprites(bool mask) { if (m_sprite_count == 0) return; @@ -603,58 +423,30 @@ void wswan_video_device::handle_sprites(int mask) for (int i = m_sprite_first + m_sprite_count - 1; i >= m_sprite_first; i--) { const u16 tile_data = m_sprite_table_buffer[i * 2]; + const bool pri = BIT(tile_data, 13); const u8 y = m_sprite_table_buffer[(i * 2) + 1] & 0xff; const u8 x = m_sprite_table_buffer[(i * 2) + 1] >> 8; int tile_line = (m_current_line - y) & 0xff; - if ((tile_line >= 0) && (tile_line < 8) && ((tile_data & 0x2000) == mask)) + if ((tile_line >= 0) && (tile_line < 8) && (pri == mask)) { u32 plane0 = 0, plane1 = 0, plane2 = 0, plane3 = 0; - int x_offset; const int tile_number = tile_data & 0x01ff; const int tile_palette = 8 + ((tile_data >> 9) & 0x07); - int check_clip = 0; + const u16 window = BIT(tile_data, 12); + bool check_clip = false; - if (tile_data & 0x8000) + if (BIT(tile_data, 15)) tile_line = 7 - tile_line; - if (m_colors_16) - { - const u16 tile_address = 0x2000 + (tile_number * 16) + (tile_line << 1); - if (m_tile_packed) - { - plane0 = (swapendian_int16(m_vram[tile_address]) << 16) | swapendian_int16(m_vram[tile_address + 1]); - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = (m_vram[tile_address + 1] & 0xff) << 2; - plane3 = (m_vram[tile_address + 1] & 0xff00) >> 5; - } - } - else - { - const u16 tile_address = 0x1000 + (tile_number * 8) + tile_line; - if (m_tile_packed) - { - plane0 = m_vram[tile_address]; - } - else - { - plane0 = m_vram[tile_address] & 0xff; - plane1 = (m_vram[tile_address] & 0xff00) >> 7; - plane2 = 0; - plane3 = 0; - } - } + get_planes(false, tile_number, tile_line, plane0, plane1, plane2, plane3); if (m_window_sprites_enable) { - if (tile_data & 0x1000) + if (window) { if (m_current_line >= m_window_sprites_top && m_current_line <= m_window_sprites_bottom) - check_clip = 1; + check_clip = true; } else { @@ -665,39 +457,19 @@ void wswan_video_device::handle_sprites(int mask) for (int j = 0; j < 8; j++) { - int col; - if (m_tile_packed) - { - if (m_colors_16) - { - col = plane0 & 0x0f; - plane0 = plane0 >> 4; - } - else - { - col = plane0 & 0x03; - plane0 = plane0 >> 2; - } - } - else - { - col = (plane3 & 8) | (plane2 & 4) | (plane1 & 2) | (plane0 & 1); - plane3 = plane3 >> 1; - plane2 = plane2 >> 1; - plane1 = plane1 >> 1; - plane0 = plane0 >> 1; - } + const u8 col = extract_planes(plane0, plane1, plane2, plane3); - if (tile_data & 0x4000) + int x_offset; + if (BIT(tile_data, 14)) x_offset = x + j; else x_offset = x + 7 - j; - x_offset = x_offset & 0xff; + x_offset &= 0xff; if (m_window_sprites_enable) { - if (tile_data & 0x1000 && check_clip) + if (window && check_clip) { if (x_offset >= m_window_sprites_left && x_offset <= m_window_sprites_right) continue; @@ -712,23 +484,7 @@ void wswan_video_device::handle_sprites(int mask) } if (x_offset >= 0 && x_offset < WSWAN_X_PIXELS) { - if (m_colors_16) - { - if (col) - { - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - } - } - else - { - if (col || !(tile_palette & 4)) - { - if (m_color_mode) - m_bitmap.pix(m_current_line, x_offset) = m_pal[tile_palette][col]; - else - m_bitmap.pix(m_current_line, x_offset) = m_main_palette[m_pal[tile_palette][col]]; - } - } + draw_pixel(x_offset, tile_palette, col); } } } @@ -743,14 +499,11 @@ void wswan_video_device::refresh_scanline() rectangle rec(0, WSWAN_X_PIXELS, m_current_line, m_current_line); if (m_lcd_control) { - 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); + m_bitmap.fill(m_color_mode ? m_bg_control : BG_COLOR, rec); } else { - m_bitmap.fill(0, rec); + m_bitmap.fill(is_color_vdp() ? (256 + (m_color_mode ? 1 : 0)) : (BG_COLOR + 1), rec); return; } @@ -760,7 +513,7 @@ void wswan_video_device::refresh_scanline() // Draw sprites between background and foreground layers if (m_sprites_enable) - handle_sprites(0); + handle_sprites(false); // Draw foreground layer, taking window settings into account if (m_layer_fg_enable) @@ -771,7 +524,7 @@ void wswan_video_device::refresh_scanline() draw_foreground_0(); break; case 1: // ??? - logerror("Unknown foreground mode 1 set\n"); + LOGUNKNOWN("Unknown foreground mode 1 set\n"); break; case 2: // FG only inside window area if (m_current_line >= m_window_fg_top && m_current_line <= m_window_fg_bottom) @@ -788,7 +541,7 @@ void wswan_video_device::refresh_scanline() // Draw sprites in front of foreground layer if (m_sprites_enable) - handle_sprites(0x2000); + handle_sprites(true); } @@ -802,7 +555,7 @@ u32 wswan_video_device::screen_update(screen_device &screen, bitmap_ind16 &bitma u16 wswan_video_device::reg_r(offs_t offset, u16 mem_mask) { - u16 value = m_regs[offset & 0x7f]; + const u16 value = m_regs[offset & 0x7f]; switch (offset) { @@ -836,10 +589,10 @@ void wswan_video_device::reg_w(offs_t offset, u16 data, u16 mem_mask) // Bit 6-7 - Unknown if (ACCESSING_BITS_0_7) { - m_layer_bg_enable = data & 0x1; - m_layer_fg_enable = (data & 0x2) >> 1; - m_sprites_enable = (data & 0x4) >> 2; - m_window_sprites_enable = (data & 0x8) >> 3; + m_layer_bg_enable = BIT(data, 0); + m_layer_fg_enable = BIT(data, 1); + m_sprites_enable = BIT(data, 2); + m_window_sprites_enable = BIT(data, 3); m_window_fg_mode = (data & 0x30) >> 4; } // Background colour @@ -855,7 +608,7 @@ void wswan_video_device::reg_w(offs_t offset, u16 data, u16 mem_mask) case 0x02 / 2: // Current scanline (read-only) if (ACCESSING_BITS_0_7) - logerror("Write to current scanline! Current value: %d Data to write: %d\n", m_current_line, data); + LOGSCANLINE("Write to current scanline! Current value: %d Data to write: %d\n", m_current_line, data); // Line compare if (ACCESSING_BITS_8_15) m_line_compare = data >> 8; @@ -865,12 +618,7 @@ void wswan_video_device::reg_w(offs_t offset, u16 data, u16 mem_mask) // Bit 0-5 - Determine sprite table base address 0 0xxxxxx0 00000000 // Bit 6-7 - Unknown if (ACCESSING_BITS_0_7) - { - if (m_vdp_type == VDP_TYPE_WSC && !m_color_mode) - m_sprite_table_address = (data & 0x3f) << 8; - else - m_sprite_table_address = (data & 0x1f) << 8; - } + m_sprite_table_address = (data & (is_color_vdp() ? 0x3f : 0x1f)) << 8; // First sprite number (the one we start drawing with) if (ACCESSING_BITS_8_15) m_sprite_first_latch = data >> 8; @@ -880,14 +628,12 @@ void wswan_video_device::reg_w(offs_t offset, u16 data, u16 mem_mask) if (ACCESSING_BITS_0_7) m_sprite_count_latch = data & 0xff; // Background/Foreground table base addresses - // Bit 8-10 - Determine background table base address 00xxx000 00000000 (in bytes) - // Bit 11 - Unknown - // Bit 12-14 - Determine foreground table base address 00xxx000 00000000 (in bytes) - // Bit 15 - Unknown + // Bit 8-11 - Determine background table base address 0xxxx000 00000000 (in bytes) + // Bit 12-15 - Determine foreground table base address 0xxxx000 00000000 (in bytes) if (ACCESSING_BITS_8_15) { - m_layer_bg_address = (data & 0x0700) << 2; - m_layer_fg_address = (data & 0x7000) >> 2; + m_layer_bg_address = (data & (is_color_vdp() ? 0x0f00 : 0x0700)) << 2; + m_layer_fg_address = (data & (is_color_vdp() ? 0xf000 : 0x7000)) >> 2; } break; case 0x08 / 2: @@ -962,36 +708,20 @@ void wswan_video_device::reg_w(offs_t offset, u16 data, u16 mem_mask) // Bit 4-7 - Gray tone setting for main palette index 1 if (ACCESSING_BITS_0_7) { - if (m_vdp_type == VDP_TYPE_WSC) - { - int i = 15 - (data & 0x0f); - int j = 15 - ((data >> 4) & 0x0f); - m_main_palette[0] = (i << 8) | (i << 4) | i; - m_main_palette[1] = (j << 8) | (j << 4) | j; - } - else - { - m_main_palette[0] = data & 0x0f; - m_main_palette[1] = (data >> 4) & 0x0f; - } + int i = pal4bit(15 - (data & 0x0f)); + int j = pal4bit(15 - ((data >> 4) & 0x0f)); + set_indirect_color(0, rgb_t(i, i, i)); + set_indirect_color(1, rgb_t(j, j, j)); } // Palette colors 2 and 3 // Bit 8-11 - Gray tone setting for main palette index 2 // Bit 12-15 - Gray tone setting for main palette index 3 if (ACCESSING_BITS_8_15) { - if (m_vdp_type == VDP_TYPE_WSC) - { - int i = 15 - ((data >> 8) & 0x0f); - int j = 15 - ((data >> 12) & 0x0f); - m_main_palette[2] = (i << 8) | (i << 4) | i; - m_main_palette[3] = (j << 8) | (j << 4) | j; - } - else - { - m_main_palette[2] = (data >> 8) & 0x0f; - m_main_palette[3] = (data >> 12) & 0x0f; - } + int i = pal4bit(15 - ((data >> 8) & 0x0f)); + int j = pal4bit(15 - ((data >> 12) & 0x0f)); + set_indirect_color(2, rgb_t(i, i, i)); + set_indirect_color(3, rgb_t(j, j, j)); } break; case 0x1e / 2: @@ -1000,36 +730,20 @@ void wswan_video_device::reg_w(offs_t offset, u16 data, u16 mem_mask) // Bit 4-7 - Gray tone setting for main palette index 5 if (ACCESSING_BITS_0_7) { - if (m_vdp_type == VDP_TYPE_WSC) - { - int i = 15 - (data & 0x0f); - int j = 15 - ((data >> 4) & 0x0f); - m_main_palette[4] = (i << 8) | (i << 4) | i; - m_main_palette[5] = (j << 8) | (j << 4) | j; - } - else - { - m_main_palette[4] = data & 0x0f; - m_main_palette[5] = (data >> 4) & 0x0f; - } + int i = pal4bit(15 - (data & 0x0f)); + int j = pal4bit(15 - ((data >> 4) & 0x0f)); + set_indirect_color(4, rgb_t(i, i, i)); + set_indirect_color(5, rgb_t(j, j, j)); } // 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 (ACCESSING_BITS_8_15) { - if (m_vdp_type == VDP_TYPE_WSC) - { - int i = 15 - ((data >> 8) & 0x0f); - int j = 15 - ((data >> 12) & 0x0f); - m_main_palette[6] = (i << 8) | (i << 4) | i; - m_main_palette[7] = (j << 8) | (j << 4) | j; - } - else - { - m_main_palette[6] = (data >> 8) & 0x0f; - m_main_palette[7] = (data >> 12) & 0x0f; - } + int i = pal4bit(15 - ((data >> 8) & 0x0f)); + int j = pal4bit(15 - ((data >> 12) & 0x0f)); + set_indirect_color(6, rgb_t(i, i, i)); + set_indirect_color(7, rgb_t(j, j, j)); } break; case 0x20 / 2: case 0x22 / 2: case 0x24 / 2: case 0x26 / 2: @@ -1058,14 +772,12 @@ void wswan_video_device::reg_w(offs_t offset, u16 data, u16 mem_mask) // 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 (ACCESSING_BITS_0_7) + if (is_color_vdp() && ACCESSING_BITS_0_7) { - if (m_vdp_type == VDP_TYPE_WSC) - { - m_color_mode = data & 0x80; - m_colors_16 = data & 0x40; - m_tile_packed = data & 0x20; - } + m_color_mode = BIT(data, 7); + m_colors_16 = BIT(data, 6); + m_tile_packed = BIT(data, 5); + m_color_mode_cb(m_color_mode); } break; case 0xa2 / 2: @@ -1117,12 +829,9 @@ TIMER_CALLBACK_MEMBER(wswan_video_device::scanline_interrupt) } } - // Handle Sound DMA - m_snd_dma_cb(); - if (m_current_line == 144) // buffer sprite table { - memcpy(m_sprite_table_buffer, &m_vram[m_sprite_table_address], 512); + memcpy(m_sprite_table_buffer, &m_vram[m_sprite_table_address & (m_color_mode ? 0x3fff : 0x1fff)], 512); m_sprite_first = m_sprite_first_latch; m_sprite_count = m_sprite_count_latch; } @@ -1155,11 +864,14 @@ TIMER_CALLBACK_MEMBER(wswan_video_device::scanline_interrupt) u16 wswan_video_device::vram_r(offs_t offset, u16 mem_mask) { - return m_vram[offset]; + return ((!m_color_mode) && (offset >= (0x4000 >> 1))) ? 0x9090 : m_vram[offset]; } void wswan_video_device::vram_w(offs_t offset, u16 data, u16 mem_mask) { + if ((!m_color_mode) && (offset >= (0x4000 >> 1))) + return; + COMBINE_DATA(&m_vram[offset]); } diff --git a/src/mame/bandai/wswan_v.h b/src/mame/bandai/wswan_v.h index 613d9007348..1f5c19c812c 100644 --- a/src/mame/bandai/wswan_v.h +++ b/src/mame/bandai/wswan_v.h @@ -16,19 +16,16 @@ #pragma once -class wswan_video_device : public device_t, public device_video_interface +class wswan_video_device : public device_t, public device_video_interface, public device_palette_interface { public: typedef device_delegate<void (int irq)> irq_cb_delegate; - typedef device_delegate<void ()> dmasnd_cb_delegate; wswan_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); ~wswan_video_device(); // static configuration template <typename... T> void set_irq_callback(T &&... args) { m_set_irq_cb.set(std::forward<T>(args)...); } - template <typename... T> void set_dmasnd_callback(T &&... args) { m_snd_dma_cb.set(std::forward<T>(args)...); } - void set_vdp_type(int type) { m_vdp_type = type; } u32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); @@ -38,36 +35,45 @@ public: void reg_w(offs_t offset, u16 data, u16 mem_mask); auto icons_cb() { return m_icons_cb.bind(); } + auto color_mode_cb() { return m_color_mode_cb.bind(); } - enum - { - VDP_TYPE_WSWAN = 0, - VDP_TYPE_WSC - }; + bool color_mode() { return m_color_mode; } static const u16 WSWAN_X_PIXELS = (28*8); static const u16 WSWAN_Y_PIXELS = (18*8); protected: + wswan_video_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int vdp_type); + // device-level overrides virtual void device_start() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; + virtual u32 palette_entries() const noexcept override { return 2 + 64; } + virtual u32 palette_indirect_entries() const noexcept override { return 8 + 1; } + + bool is_color_vdp() { return m_vdp_type == VDP_TYPE_WSC; } + + void init_palettes(); void setup_palettes(); + void get_tile_data(u16 map_addr, u8 scrolly, u16 &data, u16 &number, u16 &palette, int &line); + void get_planes(bool bank, u32 number, int line, u32 &plane0, u32 &plane1, u32 &plane2, u32 &plane3); + u8 extract_planes(u32 &plane0, u32 &plane1, u32 &plane2, u32 &plane3); + int get_xoffset(bool hflip, int x, int column, u8 scrollx); + void draw_pixel(int x_offset, u8 tile_palette, u8 pixel); void draw_background(); void draw_foreground_0(); void draw_foreground_2(); void draw_foreground_3(); - void handle_sprites(int mask); + void handle_sprites(bool mask); void refresh_scanline(); TIMER_CALLBACK_MEMBER(scanline_interrupt); - void common_save(); bitmap_ind16 m_bitmap; - u8 m_layer_bg_enable; // Background layer on/off - u8 m_layer_fg_enable; // Foreground layer on/off - u8 m_sprites_enable; // Sprites on/off - u8 m_window_sprites_enable; // Sprite window on/off + bool m_layer_bg_enable; // Background layer on/off + bool m_layer_fg_enable; // Foreground layer on/off + bool m_sprites_enable; // Sprites on/off + bool m_window_sprites_enable; // Sprite window on/off u8 m_window_fg_mode; // 0:inside/outside, 1:??, 2:inside, 3:outside u8 m_bg_control; u8 m_current_line; // Current scanline : 0-158 (159?) @@ -93,45 +99,61 @@ protected: u8 m_layer_fg_scroll_x; // Foreground layer X scroll u8 m_layer_fg_scroll_y; // Foreground layer Y scroll u8 m_lcd_control; // LCD on/off - u8 m_color_mode; // monochrome/color mode - u8 m_colors_16; // 4/16 colors mode - u8 m_tile_packed; // layered/packed tile mode switch - u8 m_timer_hblank_enable; // Horizontal blank interrupt on/off - u8 m_timer_hblank_mode; // Horizontal blank timer mode + bool m_color_mode; // monochrome/color mode + bool m_colors_16; // 4/16 colors mode + bool m_tile_packed; // layered/packed tile mode switch + bool m_timer_hblank_enable; // Horizontal blank interrupt on/off + bool m_timer_hblank_mode; // Horizontal blank timer mode u16 m_timer_hblank_reload; // Horizontal blank timer reload value u16 m_timer_hblank_count; // Horizontal blank timer counter value - u8 m_timer_vblank_enable; // Vertical blank interrupt on/off - u8 m_timer_vblank_mode; // Vertical blank timer mode + bool m_timer_vblank_enable; // Vertical blank interrupt on/off + bool m_timer_vblank_mode; // Vertical blank timer mode u16 m_timer_vblank_reload; // Vertical blank timer reload value u16 m_timer_vblank_count; // Vertical blank timer counter value - int m_main_palette[8]; emu_timer *m_timer; - std::vector<u16> m_vram; - u16 *m_palette_vram; + std::unique_ptr<u16 []> m_vram; u16 m_palette_port[0x10]; - int m_pal[16][16]; u16 m_regs[128]; irq_cb_delegate m_set_irq_cb; - dmasnd_cb_delegate m_snd_dma_cb; - int m_vdp_type; + const int m_vdp_type; devcb_write8 m_icons_cb; + devcb_write_line m_color_mode_cb; // interrupt flags - // these are the same as the wswan.h ones + // these are the same as the bandai/wswan.cpp ones static constexpr u8 WSWAN_VIDEO_IFLAG_LCMP = 0x10; static constexpr u8 WSWAN_VIDEO_IFLAG_VBLTMR = 0x20; static constexpr u8 WSWAN_VIDEO_IFLAG_VBL = 0x40; static constexpr u8 WSWAN_VIDEO_IFLAG_HBLTMR = 0x80; - static constexpr size_t WS_VRAM_SIZE = 0x4000 >> 1; - static constexpr size_t WSC_VRAM_SIZE = 0x10000 >> 1; static constexpr size_t WSC_VRAM_PALETTE = 0xfe00 >> 1; + + static constexpr u16 BG_COLOR = 64; // background color of wonderswan mono + static constexpr u16 COLOR_12BIT = 8; // 12 bit color table of wonderswan color + + enum + { + VDP_TYPE_WSWAN = 0, + VDP_TYPE_WSC + }; +}; + +class wswan_color_video_device : public wswan_video_device +{ +public: + wswan_color_video_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device-level overrides + virtual u32 palette_entries() const noexcept override { return 2 + 256; } + virtual u32 palette_indirect_entries() const noexcept override { return 8 + 4096; } }; DECLARE_DEVICE_TYPE(WSWAN_VIDEO, wswan_video_device) +DECLARE_DEVICE_TYPE(WSWAN_COLOR_VIDEO, wswan_color_video_device) #endif // MAME_BANDAI_WSWAN_V_H diff --git a/src/mame/shared/wswansound.cpp b/src/mame/shared/wswansound.cpp index 68f8bfeb990..73c42b7d520 100644 --- a/src/mame/shared/wswansound.cpp +++ b/src/mame/shared/wswansound.cpp @@ -17,6 +17,18 @@ The noise taps and behavior are the same as the Virtual Boy. #include "wswansound.h" +#define LOG_UNKNOWN (1 << 1) +#define LOG_HYPERVOICE (1 << 2) + +#define LOG_ALL (LOG_UNKNOWN | LOG_HYPERVOICE) + +#define VERBOSE (0) + +#include "logmacro.h" + +#define LOGUNKNOWN(...) LOGMASKED(LOG_UNKNOWN, __VA_ARGS__) +#define LOGHYPERVOICE(...) LOGMASKED(LOG_HYPERVOICE, __VA_ARGS__) + // device type definition DEFINE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device, "wswan_sound", "WonderSwan Custom Sound") @@ -35,26 +47,28 @@ wswan_sound_device::wswan_sound_device(const machine_config &mconfig, const char device_rom_interface(mconfig, *this), m_channel(nullptr), m_sweep_step(0), - m_sweep_time(0), + m_sweep_time(8192), m_sweep_count(0), m_noise_type(0), - m_noise_reset(0), m_noise_enable(0), m_noise_output(0), m_sample_address(0), m_audio2_voice(0), m_audio3_sweep(0), m_audio4_noise(0), - m_mono(0), - m_output_volume(0), - m_external_stereo(0), - m_external_speaker(0), + m_speaker_enable(0), + m_speaker_volume(0), + m_headphone_enable(0), + m_headphone_connected(0), m_noise_shift(0), - m_master_volume(0) + m_sample_volume(0), + m_system_volume(0), + m_loutput(0), + m_routput(0) { } -static constexpr int clk_div = 64; +static constexpr int clk_div = 128; //------------------------------------------------- // device_start - device-specific startup @@ -68,19 +82,20 @@ void wswan_sound_device::device_start() save_item(NAME(m_sweep_time)); save_item(NAME(m_sweep_count)); save_item(NAME(m_noise_type)); - save_item(NAME(m_noise_reset)); save_item(NAME(m_noise_enable)); save_item(NAME(m_sample_address)); save_item(NAME(m_audio2_voice)); save_item(NAME(m_audio3_sweep)); save_item(NAME(m_audio4_noise)); - save_item(NAME(m_mono)); - save_item(NAME(m_output_volume)); - save_item(NAME(m_external_stereo)); - save_item(NAME(m_external_speaker)); + save_item(NAME(m_speaker_enable)); + save_item(NAME(m_speaker_volume)); + save_item(NAME(m_headphone_enable)); + save_item(NAME(m_headphone_connected)); save_item(NAME(m_noise_shift)); - save_item(NAME(m_master_volume)); + save_item(NAME(m_sample_volume)); save_item(NAME(m_system_volume)); + save_item(NAME(m_loutput)); + save_item(NAME(m_routput)); save_item(STRUCT_MEMBER(m_audio, freq)); save_item(STRUCT_MEMBER(m_audio, period)); save_item(STRUCT_MEMBER(m_audio, pos)); @@ -89,6 +104,17 @@ void wswan_sound_device::device_start() save_item(STRUCT_MEMBER(m_audio, on)); save_item(STRUCT_MEMBER(m_audio, offset)); save_item(STRUCT_MEMBER(m_audio, signal)); + save_item(NAME(m_hypervoice.loutput)); + save_item(NAME(m_hypervoice.routput)); + save_item(NAME(m_hypervoice.linput)); + save_item(NAME(m_hypervoice.rinput)); + save_item(NAME(m_hypervoice.input_channel)); + save_item(NAME(m_hypervoice.volume)); + save_item(NAME(m_hypervoice.scale_mode)); + save_item(NAME(m_hypervoice.div)); + save_item(NAME(m_hypervoice.counter)); + save_item(NAME(m_hypervoice.enable)); + save_item(NAME(m_hypervoice.channel_mode)); } void wswan_sound_device::device_clock_changed() @@ -109,17 +135,21 @@ void wswan_sound_device::device_reset() { for (int i = 0; i < 4; i++) { - m_audio[i].on = 0; + m_audio[i].on = false; m_audio[i].signal = 0; m_audio[i].offset = 0; m_audio[i].pos = 0; } m_noise_output = 0; + m_hypervoice.enable = false; + m_hypervoice.counter = 0; + m_hypervoice.loutput = m_hypervoice.routput = m_hypervoice.linput = m_hypervoice.rinput = 0; + m_hypervoice.input_channel = false; } -int wswan_sound_device::fetch_sample(int channel, int offset) +u8 wswan_sound_device::fetch_sample(int channel, int offset) { - u16 w = read_word(m_sample_address + ((channel & 3) << 4) + ((offset >> 1) & 0x0e)); + u16 const w = read_word(m_sample_address + ((channel & 3) << 4) + ((offset >> 1) & 0x0e)); return (w >> ((offset & 0x03) * 4)) & 0x0f; } @@ -134,101 +164,240 @@ void wswan_sound_device::sound_stream_update(sound_stream &stream, std::vector<r auto &outputr = outputs[1]; for (int sampindex = 0; sampindex < outputl.samples(); sampindex++) { - s32 left = 0, right = 0; - - if (m_audio[0].on) + m_loutput = m_routput = 0; + if (m_headphone_connected ? m_headphone_enable : m_speaker_enable) { - s32 sample = m_audio[0].signal; - m_audio[0].pos += clk_div; - if (m_audio[0].pos >= m_audio[0].period) + if (m_audio[0].on) { - m_audio[0].pos -= m_audio[0].period; - m_audio[0].signal = fetch_sample(0, m_audio[0].offset++); + u8 const sample = m_audio[0].signal; + m_audio[0].pos += clk_div; + while (m_audio[0].pos >= m_audio[0].period) + { + m_audio[0].pos -= m_audio[0].period; + m_audio[0].signal = fetch_sample(0, m_audio[0].offset++); + } + m_loutput += m_audio[0].vol_left * sample; + m_routput += m_audio[0].vol_right * sample; } - left += m_audio[0].vol_left * sample; - right += m_audio[0].vol_right * sample; - } - if (m_audio[1].on) - { - if (m_audio2_voice) + if (m_audio[1].on) { - u8 voice_data = (m_audio[1].vol_left << 4) | m_audio[1].vol_right; - left += voice_data * (m_master_volume & 0x0f); - right += voice_data * (m_master_volume & 0x0f); + if (m_audio2_voice) + { + u8 const voice_data = (m_audio[1].vol_left << 4) | m_audio[1].vol_right; + if (m_sample_volume & 0xc) + m_loutput += voice_data >> u8(BIT(m_sample_volume, 3) ? 0 : (BIT(m_sample_volume, 2) ? 1 : ~0)); + if (m_sample_volume & 0x3) + m_routput += voice_data >> u8(BIT(m_sample_volume, 1) ? 0 : (BIT(m_sample_volume, 0) ? 1 : ~0)); + } + else + { + u8 const sample = m_audio[1].signal; + m_audio[1].pos += clk_div; + while (m_audio[1].pos >= m_audio[1].period) + { + m_audio[1].pos -= m_audio[1].period; + m_audio[1].signal = fetch_sample(1, m_audio[1].offset++); + } + m_loutput += m_audio[1].vol_left * sample; + m_routput += m_audio[1].vol_right * sample; + } } - else + + if (m_audio[2].on) { - s32 sample = m_audio[1].signal; - m_audio[1].pos += clk_div; - if (m_audio[1].pos >= m_audio[1].period) + u8 const sample = m_audio[2].signal; + m_audio[2].pos += clk_div; + while (m_audio[2].pos >= m_audio[2].period) + { + m_audio[2].pos -= m_audio[2].period; + m_audio[2].signal = fetch_sample(2, m_audio[2].offset++); + } + if (m_audio3_sweep && m_sweep_time) { - m_audio[1].pos -= m_audio[1].period; - m_audio[1].signal = fetch_sample(1, m_audio[1].offset++); + m_sweep_count += clk_div; + while (m_sweep_count >= m_sweep_time) + { + m_sweep_count -= m_sweep_time; + m_audio[2].freq += m_sweep_step; + m_audio[2].freq &= 0x7ff; + m_audio[2].period = 2048 - m_audio[2].freq; + } } - left += m_audio[1].vol_left * sample; - right += m_audio[1].vol_right * sample; + m_loutput += m_audio[2].vol_left * sample; + m_routput += m_audio[2].vol_right * sample; } - } - if (m_audio[2].on) - { - s32 sample = m_audio[2].signal; - m_audio[2].pos += clk_div; - if (m_audio[2].pos >= m_audio[2].period) + if (m_audio[3].on) { - m_audio[2].pos -= m_audio[2].period; - m_audio[2].signal = fetch_sample(2, m_audio[2].offset++); + u8 const sample = m_audio[3].signal; + m_audio[3].pos += clk_div; + while (m_audio[3].pos >= m_audio[3].period) + { + if (m_audio4_noise) + m_audio[3].signal = m_noise_output ? 0xf : 0; + else + m_audio[3].signal = fetch_sample(3, m_audio[3].offset++); + + m_audio[3].pos -= m_audio[3].period; + + if (m_noise_enable) + { + static const int shift_bit[8] = { 14, 10, 13, 4, 8, 6, 9, 11 }; + + m_noise_output = (1 ^ (m_noise_shift >> 7) ^ (m_noise_shift >> shift_bit[m_noise_type])) & 1; + m_noise_shift = m_noise_shift << 1 | m_noise_output; + } + } + m_loutput += m_audio[3].vol_left * sample; + m_routput += m_audio[3].vol_right * sample; } - if (m_audio3_sweep && m_sweep_time) + if (m_headphone_connected) { - m_sweep_count += clk_div; - if (m_sweep_count >= m_sweep_time) + s32 left = m_loutput << 5; + s32 right = m_routput << 5; + if (m_hypervoice.enable) { - m_sweep_count -= m_sweep_time; - m_audio[2].freq += m_sweep_step; - m_audio[2].freq &= 0x7ff; - m_audio[2].period = 2048 - m_audio[2].freq; + static const u8 hypervoice_div[8] = { 1, 2, 3, 4, 5, 6, 8, 12 }; + + left += m_hypervoice.loutput; + right += m_hypervoice.routput; + if (++m_hypervoice.counter >= hypervoice_div[m_hypervoice.div]) + { + m_hypervoice.loutput = m_hypervoice.scale(m_hypervoice.linput); + m_hypervoice.routput = m_hypervoice.scale(m_hypervoice.rinput); + m_hypervoice.counter = 0; + } } + // TODO: clamped? + outputl.put_int_clamp(sampindex, left, 32768); + outputr.put_int_clamp(sampindex, right, 32768); + } + else + { + u8 const mono = (((m_loutput & 0x3ff) + (m_routput & 0x3ff)) >> m_speaker_volume) & 0xff; + outputl.put_int(sampindex, mono, 256); + outputr.put_int(sampindex, mono, 256); } - left += m_audio[2].vol_left * sample; - right += m_audio[2].vol_right * sample; } - - if (m_audio[3].on) + else { - s32 sample = m_audio[3].signal; - m_audio[3].pos += clk_div; - if (m_audio[3].pos >= m_audio[3].period) - { - if (m_audio4_noise) - m_audio[3].signal = m_noise_output ? 0xf : 0; - else - m_audio[3].signal = fetch_sample(3, m_audio[3].offset++); + outputl.put(sampindex, 0.0); + outputr.put(sampindex, 0.0); + } + } +} - m_audio[3].pos -= m_audio[3].period; - if (m_noise_reset) - { - m_noise_reset = 0; - m_noise_shift = 0; - m_noise_output = 0; - } +void wswan_sound_device::hypervoice_t::stereo_input(u8 input) +{ + if (input_channel) // Right input + rinput = input; + else // Left input + linput = input; + input_channel = !input_channel; +} - if (m_noise_enable) - { - static int shift_bit[] = { 14, 10, 13, 4, 8, 6, 9, 11 }; - m_noise_output = (1 ^ (m_noise_shift >> 7) ^ (m_noise_shift >> shift_bit[m_noise_type])) & 1; - m_noise_shift = m_noise_shift << 1 | m_noise_output; - } - } - left += m_audio[3].vol_left * sample; - right += m_audio[3].vol_right * sample; - } +s32 wswan_sound_device::hypervoice_t::scale(u8 input) +{ + s32 output = 0; + switch (scale_mode) + { + case 0x00: // Unsigned + output = input << 8; + break; + case 0x01: // Unsigned negated + output = 0xffff0000 | (input << 8); + break; + case 0x02: // Signed + output = s32(s8(input)) << 8; + break; + case 0x03: // None + output = s16(input << 8); + break; + } + return (scale_mode == 0x03) ? output : (output >> volume); +} + + +void wswan_sound_device::hypervoice_dma_w(u8 data) +{ + switch (m_hypervoice.channel_mode) + { + case 0x00: // Stereo + m_hypervoice.stereo_input(data); + break; + case 0x01: // Mono, Left + m_hypervoice.linput = data; + break; + case 0x02: // Mono, Right + m_hypervoice.rinput = data; + break; + case 0x03: // Mono, Both + m_hypervoice.linput = m_hypervoice.rinput = data; + break; + } +} + - outputl.put_int(sampindex, left, 32768 >> 5); - outputr.put_int(sampindex, right, 32768 >> 5); +u16 wswan_sound_device::hypervoice_r(offs_t offset, u16 mem_mask) +{ + offset += 0x64 / 2; + m_channel->update(); + switch (offset) + { + case 0x6a / 2: // Control + return (m_hypervoice.volume) | + (m_hypervoice.scale_mode << 2) | + (m_hypervoice.div << 4) | + (m_hypervoice.enable ? 0x0080 : 0x0000) | + (m_hypervoice.channel_mode << 13); + default: + if (!machine().side_effects_disabled()) + LOGHYPERVOICE("%s: Unknown hypervoice port read %02x & %04x", machine().describe_context(), offset << 1, mem_mask); + break; + } + return 0; +} + +void wswan_sound_device::hypervoice_w(offs_t offset, u16 data, u16 mem_mask) +{ + offset += 0x64 / 2; + m_channel->update(); + + switch (offset) + { + case 0x64 / 2: // Left output + COMBINE_DATA(&m_hypervoice.loutput); + break; + case 0x66 / 2: // Right output + COMBINE_DATA(&m_hypervoice.routput); + break; + case 0x68 / 2: // Input + if (ACCESSING_BITS_8_15) + { + m_hypervoice.stereo_input((data >> 8) & 0xff); + } + break; + case 0x6a / 2: // Control + if (ACCESSING_BITS_0_7) + { + m_hypervoice.volume = data & 3; + m_hypervoice.scale_mode = (data >> 2) & 3; + m_hypervoice.div = (data >> 4) & 7; + m_hypervoice.enable = BIT(data, 7); + } + if (ACCESSING_BITS_8_15) + { + m_hypervoice.channel_mode = (data >> 13) & 3; + if (BIT(data, 12)) + m_hypervoice.input_channel = false; + } + break; + default: + LOGHYPERVOICE("%s: Unknown hypervoice port write %02x - %04x & %04x", machine().describe_context(), offset << 1, data, mem_mask); + break; } } @@ -236,7 +405,8 @@ void wswan_sound_device::sound_stream_update(sound_stream &stream, std::vector<r u16 wswan_sound_device::port_r(offs_t offset, u16 mem_mask) { m_channel->update(); - switch (offset) { + switch (offset) + { case 0x80 / 2: case 0x82 / 2: case 0x84 / 2: @@ -251,7 +421,7 @@ u16 wswan_sound_device::port_r(offs_t offset, u16 mem_mask) case 0x8c / 2: return m_sweep_step | (((m_sweep_time / 8192) - 1) << 8); case 0x8e / 2: - return m_noise_type | (m_noise_reset ? 0x08 : 0x00) | (m_noise_enable ? 0x10 : 0x00) | + return m_noise_type | (m_noise_enable ? 0x10 : 0x00) | ((m_sample_address << 2) & 0xff00); case 0x90 / 2: return (m_audio[0].on ? 0x01 : 0x00) | @@ -261,15 +431,25 @@ u16 wswan_sound_device::port_r(offs_t offset, u16 mem_mask) (m_audio2_voice ? 0x20 : 0x00) | (m_audio3_sweep ? 0x40 : 0x00) | (m_audio4_noise ? 0x80 : 0x00) | - (m_mono ? 0x0100 : 0x00) | (m_output_volume << 9) | - (m_external_stereo ? 0x0800 : 0x00) | - (m_external_speaker ? 0x00 : 0x00); // TODO 0x80 is set when external speaker is connected + (m_speaker_enable ? 0x0100 : 0x0000) | (m_speaker_volume << 9) | + (m_headphone_enable ? 0x0800 : 0x0000) | + (m_headphone_connected ? 0x8000 : 0x0000); case 0x92 / 2: return m_noise_shift; case 0x94 / 2: - return m_master_volume; + return m_sample_volume; + case 0x96 / 2: + return m_loutput & 0x3ff; + case 0x98 / 2: + return m_routput & 0x3ff; + case 0x9a / 2: + return (m_loutput & 0x3ff) + (m_routput & 0x3ff); case 0x9e / 2: return m_system_volume; + default: + if (!machine().side_effects_disabled()) + LOGUNKNOWN("%s: Unknown sound port read %02x & %04x", machine().describe_context(), offset << 1, mem_mask); + break; } return 0; } @@ -323,12 +503,12 @@ void wswan_sound_device::port_w(offs_t offset, u16 data, u16 mem_mask) // Sweep step if (ACCESSING_BITS_0_7) { - m_sweep_step = (int8_t)(data & 0xff); + m_sweep_step = s8(data & 0xff); } // Sweep time if (ACCESSING_BITS_8_15) { - m_sweep_time = 8192 * ((data >> 8) + 1); + m_sweep_time = 8192 * (((data >> 8) & 0x1f) + 1); } break; @@ -337,8 +517,9 @@ void wswan_sound_device::port_w(offs_t offset, u16 data, u16 mem_mask) if (ACCESSING_BITS_0_7) { m_noise_type = data & 0x07; - m_noise_reset = BIT(data, 3); m_noise_enable = BIT(data, 4); + if (BIT(data, 3)) + m_noise_shift = m_noise_output = 0; } // Sample location if (ACCESSING_BITS_8_15) @@ -362,10 +543,9 @@ void wswan_sound_device::port_w(offs_t offset, u16 data, u16 mem_mask) // Audio output if (ACCESSING_BITS_8_15) { - m_mono = BIT(data, 8); - m_output_volume = ((data >> 9) & 0x03); - m_external_stereo = BIT(data, 11); - m_external_speaker = 1; + m_speaker_enable = BIT(data, 8); + m_speaker_volume = ((data >> 9) & 0x03); + m_headphone_enable = BIT(data, 11); } break; @@ -374,14 +554,19 @@ void wswan_sound_device::port_w(offs_t offset, u16 data, u16 mem_mask) m_noise_shift &= 0x7fff; break; - case 0x94 / 2: // Master volume + case 0x94 / 2: // Sample volume if (ACCESSING_BITS_0_7) - m_master_volume = data & 0xff; + m_sample_volume = data & 0x0f; + if (ACCESSING_BITS_8_15) + LOGUNKNOWN("%s: Sound Test bit set %02x\n", machine().describe_context(), (data >> 8) & 0xff); break; case 0x9e / 2: // WSC volume setting (0, 1, 2, 3) (TODO) if (ACCESSING_BITS_0_7) m_system_volume = data & 0x03; break; + default: + LOGUNKNOWN("%s: Unknown hypervoice port write %02x - %04x & %04x", machine().describe_context(), offset << 1, data, mem_mask); + break; } } diff --git a/src/mame/shared/wswansound.h b/src/mame/shared/wswansound.h index 84bafc90f74..f300a597b29 100644 --- a/src/mame/shared/wswansound.h +++ b/src/mame/shared/wswansound.h @@ -21,19 +21,37 @@ class wswan_sound_device : public device_t, public: wswan_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + void set_headphone_connected(bool headphone_connected) { m_headphone_connected = headphone_connected; } + + void hypervoice_dma_w(u8 data); + + void hypervoice_w(offs_t offset, u16 data, u16 mem_mask); + u16 hypervoice_r(offs_t offset, u16 mem_mask); + void port_w(offs_t offset, u16 data, u16 mem_mask); u16 port_r(offs_t offset, u16 mem_mask); protected: - struct CHAN + // device-level overrides + virtual void device_start() override ATTR_COLD; + virtual void device_clock_changed() override; + virtual void device_reset() override ATTR_COLD; + + virtual void rom_bank_pre_change() override; + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override; + +private: + struct channel_t { - CHAN() : + channel_t() : freq(0), - period(0), + period(2048), pos(0), vol_left(0), vol_right(0), - on(0), + on(false), offset(0), signal(0) { } @@ -42,44 +60,65 @@ protected: u32 pos; u8 vol_left; u8 vol_right; - u8 on; + bool on; u8 offset; u8 signal; }; - // device-level overrides - virtual void device_start() override ATTR_COLD; - virtual void device_clock_changed() override; - virtual void device_reset() override ATTR_COLD; - - virtual void rom_bank_pre_change() override; - - // sound stream update overrides - virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override; - -private: - int fetch_sample(int channel, int offset); + struct hypervoice_t + { + hypervoice_t() : + loutput(0), + routput(0), + linput(0), + rinput(0), + input_channel(false), + volume(0), + scale_mode(0), + div(0), + counter(0), + enable(false), + channel_mode(0) {} + + void stereo_input(u8 input); + s32 scale(u8 input); + + s32 loutput; + s32 routput; + u8 linput; + u8 rinput; + bool input_channel; + u8 volume; + u8 scale_mode; + u8 div; + u8 counter; + bool enable; + u8 channel_mode; + } m_hypervoice; + + u8 fetch_sample(int channel, int offset); sound_stream *m_channel; - CHAN m_audio[4]; - s8 m_sweep_step; - u32 m_sweep_time; - u32 m_sweep_count; - u8 m_noise_type; - u8 m_noise_reset; - u8 m_noise_enable; - u8 m_noise_output; - u16 m_sample_address; - u8 m_audio2_voice; - u8 m_audio3_sweep; - u8 m_audio4_noise; - u8 m_mono; - u8 m_output_volume; - u8 m_external_stereo; - u8 m_external_speaker; - u16 m_noise_shift; - u8 m_master_volume; - u8 m_system_volume = 0; + channel_t m_audio[4]; + s8 m_sweep_step; + u32 m_sweep_time; + u32 m_sweep_count; + u8 m_noise_type; + u8 m_noise_enable; + u8 m_noise_output; + u16 m_sample_address; + u8 m_audio2_voice; + u8 m_audio3_sweep; + u8 m_audio4_noise; + u8 m_speaker_enable; + u8 m_speaker_volume; + u8 m_headphone_enable; + u8 m_headphone_connected; + u16 m_noise_shift; + u8 m_sample_volume; + u8 m_system_volume = 0; + u16 m_loutput; + u16 m_routput; }; DECLARE_DEVICE_TYPE(WSWAN_SND, wswan_sound_device) diff --git a/src/mame/virtual/vgmplay.cpp b/src/mame/virtual/vgmplay.cpp index eb39cb463e5..b3180e56271 100644 --- a/src/mame/virtual/vgmplay.cpp +++ b/src/mame/virtual/vgmplay.cpp @@ -3481,6 +3481,8 @@ void vgmplay_state::soundchips16le_map(address_map &map) map(vgmplay_device::A_C352_1, vgmplay_device::A_C352_1 + 0x7fff).w(m_c352[1], FUNC(c352_device::write)); map(vgmplay_device::A_WSWAN_0, vgmplay_device::A_WSWAN_0 + 0xff).w(m_wswan[0], FUNC(wswan_sound_device::port_w)); map(vgmplay_device::A_WSWAN_1, vgmplay_device::A_WSWAN_1 + 0xff).w(m_wswan[1], FUNC(wswan_sound_device::port_w)); + map(vgmplay_device::A_WSWAN_0 + 0x64, vgmplay_device::A_WSWAN_0 + 0x6b).w(m_wswan[0], FUNC(wswan_sound_device::hypervoice_w)); + map(vgmplay_device::A_WSWAN_1 + 0x64, vgmplay_device::A_WSWAN_1 + 0x6b).w(m_wswan[1], FUNC(wswan_sound_device::hypervoice_w)); map(vgmplay_device::A_WSWAN_RAM_0, vgmplay_device::A_WSWAN_RAM_0 + 0x3fff).ram().share("wswan_ram.0"); map(vgmplay_device::A_WSWAN_RAM_1, vgmplay_device::A_WSWAN_RAM_1 + 0x3fff).ram().share("wswan_ram.1"); } @@ -4005,11 +4007,13 @@ void vgmplay_state::vgmplay(machine_config &config) m_scsp[1]->add_route(1, m_mixer, 1, AUTO_ALLOC_INPUT, 1); WSWAN_SND(config, m_wswan[0], 0); + m_wswan[0]->set_headphone_connected(true); m_wswan[0]->set_addrmap(0, &vgmplay_state::wswan_map<0>); m_wswan[0]->add_route(0, m_mixer, 0.50, AUTO_ALLOC_INPUT, 0); m_wswan[0]->add_route(1, m_mixer, 0.50, AUTO_ALLOC_INPUT, 1); WSWAN_SND(config, m_wswan[1], 0); + m_wswan[1]->set_headphone_connected(true); m_wswan[1]->set_addrmap(0, &vgmplay_state::wswan_map<1>); m_wswan[1]->add_route(0, m_mixer, 0.50, AUTO_ALLOC_INPUT, 0); m_wswan[1]->add_route(1, m_mixer, 0.50, AUTO_ALLOC_INPUT, 1); |