summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author cam900 <dbtlrchl@naver.com>2025-04-09 06:30:15 +0900
committer GitHub <noreply@github.com>2025-04-09 07:30:15 +1000
commit7214b1d7485050a6bb227cc7a7d2d4a6548bda6b (patch)
tree3398f841f2202528cc98401976cef441965350bc
parentbe3a4c60dc68c20ece1360ddf12130493489d992 (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.cpp618
-rw-r--r--src/mame/bandai/wswan_v.cpp836
-rw-r--r--src/mame/bandai/wswan_v.h84
-rw-r--r--src/mame/shared/wswansound.cpp391
-rw-r--r--src/mame/shared/wswansound.h111
-rw-r--r--src/mame/virtual/vgmplay.cpp4
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);