wswan/wscolor: Add boot rom support (#7277)

* wswan: Add boot rom. [Wilbert Pol]

* wswan: merge drivers/wswan.cpp, includes/wswan.h, and machine/wswan.cpp (nw)

* wswan: fix background color selection in wsc mode (nw)

* wswan: add defaults for the internal eeproms (nw)

* wswan: add some documentation; rename a few methods (nw)
This commit is contained in:
wilbertpol 2020-09-23 13:58:19 +02:00 committed by GitHub
parent 33a5e3ea4b
commit f773d1b656
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 749 additions and 853 deletions

View File

@ -1863,10 +1863,8 @@ files {
MAME_DIR .. "src/mame/drivers/rx78.cpp",
MAME_DIR .. "src/mame/drivers/tamag1.cpp",
MAME_DIR .. "src/mame/drivers/wswan.cpp",
MAME_DIR .. "src/mame/includes/wswan.h",
MAME_DIR .. "src/mame/audio/wswan.cpp",
MAME_DIR .. "src/mame/audio/wswan.h",
MAME_DIR .. "src/mame/machine/wswan.cpp",
MAME_DIR .. "src/mame/video/wswan.cpp",
MAME_DIR .. "src/mame/video/wswan.h",
MAME_DIR .. "src/mame/drivers/bandai_design_master.cpp",

View File

@ -12,85 +12,214 @@
Based on the WStech documentation by Judge and Dox.
Usage:
Keep START button pressed during startup (or reset) to enter the internal
configuration menu.
Known issues/TODOs:
- Get the V30MZ core into MAME, still need to remove some nec specific
instructions and fix the flags handling of the div/mul instructions.
- Add support for noise sound
- Add support for voice sound
- Add support for enveloped sound
- Perform video DMA at proper timing.
- Add sound DMA.
- Setup some reasonable values in the internal EEPROM area?
- Add (real/proper) RTC support.
- Look into timing issues like in Puzzle Bobble. VBlank interrupt lasts very long
which causes sprites to be disabled until about 10%-40% of drawing the screen.
The real unit seems to display things fine, need a real unit + real cart to
verify.
- Is background color setting really ok?
- Get a dump of the internal BIOSes.
- Swan Crystal can handle up to 512Mbit ROMs??????
- SRAM sizes should be in kbit instead of kbytes(?). This raises a few
interesting issues:
- mirror of smaller <64KBYTE/512kbit sram sizes
- banking when using 1M or 2M sram sizes
- The units likely came with the name "WONDERSWAN" configured in the
internal EEPOM
***************************************************************************/
#include "emu.h"
#include "includes/wswan.h"
#include "cpu/v30mz/v30mz.h"
#include "machine/nvram.h"
#include "audio/wswan.h"
#include "video/wswan.h"
#include "bus/wswan/slot.h"
#include "bus/wswan/rom.h"
#include "emupal.h"
#include "render.h"
#include "screen.h"
#include "softlist.h"
#include "speaker.h"
#include "wswan.lh"
void wswan_state::wswan_mem(address_map &map)
class wswan_state : public driver_device
{
public:
wswan_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_vdp(*this, "vdp"),
m_sound(*this, "custom"),
m_cart(*this, "cartslot"),
m_region_maincpu(*this, "maincpu"),
m_cursx(*this, "CURSX"),
m_cursy(*this, "CURSY"),
m_buttons(*this, "BUTTONS")
{ }
void wswan(machine_config &config);
protected:
// Interrupt flags
static const u8 WSWAN_IFLAG_STX = 0x01;
static const u8 WSWAN_IFLAG_KEY = 0x02;
static const u8 WSWAN_IFLAG_RTC = 0x04;
static const u8 WSWAN_IFLAG_SRX = 0x08;
static const u8 WSWAN_IFLAG_LCMP = 0x10;
static const u8 WSWAN_IFLAG_VBLTMR = 0x20;
static const u8 WSWAN_IFLAG_VBL = 0x40;
static const u8 WSWAN_IFLAG_HBLTMR = 0x80;
// Interrupts
static const u8 WSWAN_INT_STX = 0;
static const u8 WSWAN_INT_KEY = 1;
static const u8 WSWAN_INT_RTC = 2;
static const u8 WSWAN_INT_SRX = 3;
static const u8 WSWAN_INT_LCMP = 4;
static const u8 WSWAN_INT_VBLTMR = 5;
static const u8 WSWAN_INT_VBL = 6;
static const u8 WSWAN_INT_HBLTMR = 7;
static const u32 INTERNAL_EEPROM_SIZE = 1024; // 16kbit on WSC
static const u32 INTERNAL_EEPROM_SIZE_WS = 64; // 1kbit on WS
enum enum_system { TYPE_WSWAN=0, TYPE_WSC };
struct sound_dma_t
{
u32 source; // Source address
u16 size; // Size
u8 enable; // Enabled
};
required_device<cpu_device> m_maincpu;
required_device<wswan_video_device> m_vdp;
required_device<wswan_sound_device> m_sound;
required_device<ws_cart_slot_device> m_cart;
u8 m_ws_portram[256];
u8 m_internal_eeprom[INTERNAL_EEPROM_SIZE * 2];
u8 m_system_type;
sound_dma_t m_sound_dma;
u8 m_bios_disabled;
u8 m_rotate;
required_memory_region m_region_maincpu;
required_ioport m_cursx;
required_ioport m_cursy;
required_ioport m_buttons;
u8 bios_r(offs_t offset);
u8 port_r(offs_t offset);
void port_w(offs_t offset, u8 data);
void set_irq_line(int irq);
void dma_sound_cb();
void common_start();
virtual void machine_start() override;
virtual void machine_reset() override;
void palette(palette_device &palette) const;
void io_map(address_map &map);
void mem_map(address_map &map);
void snd_map(address_map &map);
void register_save();
void handle_irqs();
void clear_irq_line(int irq);
virtual u16 get_internal_eeprom_address();
};
class wscolor_state : public wswan_state
{
public:
using wswan_state::wswan_state;
void wscolor(machine_config &config);
protected:
virtual void machine_start() override;
void mem_map(address_map &map);
void palette(palette_device &palette) const;
virtual u16 get_internal_eeprom_address() override;
};
static const uint8_t ws_portram_init[256] =
{
0x00, 0x00, 0x00/*?*/, 0xbb, 0x00, 0x00, 0x00, 0x26, 0xfe, 0xde, 0xf9, 0xfb, 0xdb, 0xd7, 0x7f, 0xf5,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9e, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x99, 0xfd, 0xb7, 0xdf,
0x30, 0x57, 0x75, 0x76, 0x15, 0x73, 0x70/*77?*/, 0x77, 0x20, 0x75, 0x50, 0x36, 0x70, 0x67, 0x50, 0x77,
0x57, 0x54, 0x75, 0x77, 0x75, 0x17, 0x37, 0x73, 0x50, 0x57, 0x60, 0x77, 0x70, 0x77, 0x10, 0x73,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x87, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xdb, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x42, 0x00, 0x83, 0x00,
0x2f, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1
};
void wswan_state::mem_map(address_map &map)
{
map(0x00000, 0x03fff).rw(m_vdp, FUNC(wswan_video_device::vram_r), FUNC(wswan_video_device::vram_w)); // 16kb RAM / 4 colour tiles
map(0x04000, 0x0ffff).noprw(); // nothing
//map(0x10000, 0xeffff) // cart range, setup at machine_start
map(0xf0000, 0xfffff).r(FUNC(wswan_state::bios_r));
}
void wscolor_state::wscolor_mem(address_map &map)
void wscolor_state::mem_map(address_map &map)
{
map(0x00000, 0x0ffff).rw("vdp", FUNC(wswan_video_device::vram_r), FUNC(wswan_video_device::vram_w)); // 16kb RAM / 4 colour tiles, 16 colour tiles + palettes
//map(0x10000, 0xeffff) // cart range, setup at machine_start
map(0x00000, 0x0ffff).rw(m_vdp, FUNC(wswan_video_device::vram_r), FUNC(wswan_video_device::vram_w)); // 16kb RAM / 4 colour tiles, 16 colour tiles + palettes
map(0xf0000, 0xfffff).r(FUNC(wscolor_state::bios_r));
}
void wswan_state::wswan_io(address_map &map)
void wswan_state::io_map(address_map &map)
{
map(0x00, 0xff).rw(FUNC(wswan_state::port_r), FUNC(wswan_state::port_w)); // I/O ports
}
void wswan_state::wswan_snd(address_map &map)
void wswan_state::snd_map(address_map &map)
{
map(0x00000, 0x03fff).r(m_vdp, FUNC(wswan_video_device::vram_r));
}
static INPUT_PORTS_START( wswan )
PORT_START("CURSX")
PORT_BIT( 0x1, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("X1 - Up")
PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("X3 - Down")
PORT_BIT( 0x8, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_NAME("X4 - Left")
PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_NAME("X3 - Down")
PORT_BIT( 0x2, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_NAME("X2 - Right")
PORT_BIT( 0x1, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_NAME("X1 - Up")
PORT_START("BUTTONS")
PORT_BIT( 0x2, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start")
PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Button A")
PORT_BIT( 0x8, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Button B")
PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Button A")
PORT_BIT( 0x2, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start")
PORT_START("CURSY")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y1 - Up") PORT_CODE(KEYCODE_W)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y3 - Down") PORT_CODE(KEYCODE_S)
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y4 - Left") PORT_CODE(KEYCODE_A)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y3 - Down") PORT_CODE(KEYCODE_S)
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y2 - Right") PORT_CODE(KEYCODE_D)
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Y1 - Up") PORT_CODE(KEYCODE_W)
INPUT_PORTS_END
static GFXDECODE_START( gfx_wswan )
GFXDECODE_END
/* WonderSwan can display 16 shades of grey */
void wswan_state::wswan_palette(palette_device &palette) const
void wswan_state::palette(palette_device &palette) const
{
for (int i = 0; i < 16; i++)
{
@ -99,7 +228,8 @@ void wswan_state::wswan_palette(palette_device &palette) const
}
}
void wscolor_state::wscolor_palette(palette_device &palette) const
void wscolor_state::palette(palette_device &palette) const
{
for (int i = 0; i < 4096; i++)
{
@ -110,6 +240,7 @@ void wscolor_state::wscolor_palette(palette_device &palette) const
}
}
static void wswan_cart(device_slot_interface &device)
{
device.option_add_internal("ws_rom", WS_ROM_STD);
@ -117,16 +248,17 @@ static void wswan_cart(device_slot_interface &device)
device.option_add_internal("ws_eeprom", WS_ROM_EEPROM);
}
void wswan_state::wswan(machine_config &config)
{
/* Basic machine hardware */
// Basic machine hardware
V30MZ(config, m_maincpu, 3.072_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &wswan_state::wswan_mem);
m_maincpu->set_addrmap(AS_IO, &wswan_state::wswan_io);
m_maincpu->set_addrmap(AS_PROGRAM, &wswan_state::mem_map);
m_maincpu->set_addrmap(AS_IO, &wswan_state::io_map);
WSWAN_VIDEO(config, m_vdp, 0);
m_vdp->set_screen("screen");
m_vdp->set_vdp_type(VDP_TYPE_WSWAN);
m_vdp->set_vdp_type(wswan_video_device::VDP_TYPE_WSWAN);
m_vdp->set_irq_callback(FUNC(wswan_state::set_irq_line));
m_vdp->set_dmasnd_callback(FUNC(wswan_state::dma_sound_cb));
@ -136,68 +268,622 @@ void wswan_state::wswan(machine_config &config)
screen.set_screen_update("vdp", FUNC(wswan_video_device::screen_update));
// screen.set_size(WSWAN_X_PIXELS, WSWAN_Y_PIXELS);
// screen.set_visarea(0*8, WSWAN_X_PIXELS - 1, 0, WSWAN_Y_PIXELS - 1);
screen.set_raw(3.072_MHz_XTAL, 256, 0, WSWAN_X_PIXELS, 159, 0, WSWAN_Y_PIXELS);
screen.set_raw(3.072_MHz_XTAL, 256, 0, wswan_video_device::WSWAN_X_PIXELS, 159, 0, wswan_video_device::WSWAN_Y_PIXELS);
screen.set_palette("palette");
config.set_default_layout(layout_wswan);
config.set_maximum_quantum(attotime::from_hz(60));
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1);
NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0);
GFXDECODE(config, "gfxdecode", "palette", gfx_wswan);
PALETTE(config, "palette", FUNC(wswan_state::wswan_palette), 16);
PALETTE(config, "palette", FUNC(wswan_state::palette), 16);
/* sound hardware */
// sound hardware
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
WSWAN_SND(config, m_sound, 3.072_MHz_XTAL);
m_sound->set_addrmap(0, &wswan_state::wswan_snd);
m_sound->set_addrmap(0, &wswan_state::snd_map);
m_sound->add_route(0, "lspeaker", 0.50);
m_sound->add_route(1, "rspeaker", 0.50);
/* cartridge */
// cartridge
WS_CART_SLOT(config, m_cart, 3.072_MHz_XTAL / 8, wswan_cart, nullptr);
/* software lists */
// software lists
SOFTWARE_LIST(config, "cart_list").set_original("wswan");
SOFTWARE_LIST(config, "wsc_list").set_compatible("wscolor");
SOFTWARE_LIST(config, "pc2_list").set_compatible("pockchalv2");
}
void wscolor_state::wscolor(machine_config &config)
{
wswan(config);
m_maincpu->set_addrmap(AS_PROGRAM, &wscolor_state::wscolor_mem);
m_maincpu->set_addrmap(AS_PROGRAM, &wscolor_state::mem_map);
m_vdp->set_vdp_type(VDP_TYPE_WSC);
m_vdp->set_vdp_type(wswan_video_device::VDP_TYPE_WSC);
auto &palette(*subdevice<palette_device>("palette"));
palette.set_entries(4096);
palette.set_init(FUNC(wscolor_state::wscolor_palette));
palette.set_init(FUNC(wscolor_state::palette));
/* software lists */
// software lists
config.device_remove("wsc_list");
SOFTWARE_LIST(config.replace(), "cart_list").set_original("wscolor");
SOFTWARE_LIST(config, "ws_list").set_compatible("wswan");
}
void wswan_state::handle_irqs()
{
if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_HBLTMR)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_HBLTMR); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBL)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBL); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBLTMR)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBLTMR); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_LCMP)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_LCMP); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_SRX)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_SRX); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_RTC)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_RTC); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_KEY)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_KEY); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_STX)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_STX); // V30MZ
}
else
{
m_maincpu->set_input_line(0, CLEAR_LINE);
}
}
void wswan_state::set_irq_line(int irq)
{
if (m_ws_portram[0xb2] & irq)
{
m_ws_portram[0xb6] |= irq;
handle_irqs();
}
}
void wswan_state::dma_sound_cb()
{
if ((m_sound_dma.enable & 0x88) == 0x80)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
/* TODO: Output sound DMA byte */
port_w(0x89, space.read_byte(m_sound_dma.source));
m_sound_dma.size--;
m_sound_dma.source = (m_sound_dma.source + 1) & 0x0fffff;
if (m_sound_dma.size == 0)
{
m_sound_dma.enable &= 0x7f;
}
}
}
void wswan_state::clear_irq_line(int irq)
{
m_ws_portram[0xb6] &= ~irq;
handle_irqs();
}
void wswan_state::register_save()
{
save_item(NAME(m_ws_portram));
save_item(NAME(m_internal_eeprom));
save_item(NAME(m_bios_disabled));
save_item(NAME(m_rotate));
save_item(NAME(m_sound_dma.source));
save_item(NAME(m_sound_dma.size));
save_item(NAME(m_sound_dma.enable));
if (m_cart->exists())
m_cart->save_nvram();
}
void wswan_state::common_start()
{
register_save();
if (m_cart->exists())
{
// ROM
m_maincpu->space(AS_PROGRAM).install_read_handler(0x20000, 0x2ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom20)));
m_maincpu->space(AS_PROGRAM).install_read_handler(0x30000, 0x3ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom30)));
m_maincpu->space(AS_PROGRAM).install_read_handler(0x40000, 0xeffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom40)));
// SRAM
if (m_cart->get_type() == WS_SRAM)
{
m_maincpu->space(AS_PROGRAM).install_read_handler(0x10000, 0x1ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_ram)));
m_maincpu->space(AS_PROGRAM).install_write_handler(0x10000, 0x1ffff, write8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::write_ram)));
}
}
}
void wswan_state::machine_start()
{
common_start();
subdevice<nvram_device>("nvram")->set_base(m_internal_eeprom, INTERNAL_EEPROM_SIZE_WS * 2);
m_system_type = TYPE_WSWAN;
}
void wscolor_state::machine_start()
{
common_start();
subdevice<nvram_device>("nvram")->set_base(m_internal_eeprom, INTERNAL_EEPROM_SIZE * 2);
m_system_type = TYPE_WSC;
}
void wswan_state::machine_reset()
{
m_bios_disabled = 0;
if (m_cart->exists())
m_rotate = m_cart->get_is_rotated();
else
m_rotate = 0;
/* Intialize ports */
memcpy(m_ws_portram, ws_portram_init, 256);
render_target *target = machine().render().first_target();
target->set_view(m_rotate);
/* Initialize sound DMA */
memset(&m_sound_dma, 0, sizeof(m_sound_dma));
}
u8 wswan_state::bios_r(offs_t offset)
{
if (!m_bios_disabled)
return m_region_maincpu->base()[offset & (m_region_maincpu->bytes() - 1)];
else
return m_cart->read_rom40(offset + 0xb0000);
}
u8 wswan_state::port_r(offs_t offset)
{
u8 value = m_ws_portram[offset];
if (offset != 2)
logerror("PC=%X: port read %02X\n", m_maincpu->pc(), offset);
if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0))
return m_vdp->reg_r(offset);
switch (offset)
{
case 0x4a: // Sound DMA source address (low)
value = m_sound_dma.source & 0xff;
break;
case 0x4b: // Sound DMA source address (high)
value = (m_sound_dma.source >> 8) & 0xff;
break;
case 0x4c: // Sound DMA source memory segment
value = (m_sound_dma.source >> 16) & 0xff;
break;
case 0x4e: // Sound DMA transfer size (low)
value = m_sound_dma.size & 0xff;
break;
case 0x4f: // Sound DMA transfer size (high)
value = (m_sound_dma.size >> 8) & 0xff;
break;
case 0x52: // Sound DMA start/stop
value = m_sound_dma.enable;
break;
case 0x60:
value = m_vdp->reg_r(offset);
break;
case 0xa0: // Hardware type
// Bit 0 - Disable/enable Bios
// Bit 1 - Determine mono/color
// Bit 2 - Unknown, used to determine color/crystal
// Bit 3 - Unknown
// Bit 7 - Checked during start up, expects bit 7 set
value = value & ~ 0x02;
if (m_system_type == TYPE_WSC)
value |= 2;
value |= 0x80;
break;
case 0xb5: // Read controls
// Bit 0-3 - Current state of input lines (read-only)
// Bit 4-6 - Select line of inputs to read
// 001 - Read Y cursors
// 010 - Read X cursors
// 100 - Read START,A,B buttons
// Bit 7 - Unknown
value = value & 0xf0;
switch (value)
{
case 0x10: // Read Y cursors: Y1 - Y2 - Y3 - Y4
{
u8 input = m_cursy->read();
if (m_rotate) // reorient controls if the console is rotated
{
if (input & 0x01) value |= 0x02;
if (input & 0x02) value |= 0x04;
if (input & 0x04) value |= 0x08;
if (input & 0x08) value |= 0x01;
}
else
value = value | input;
}
break;
case 0x20: // Read X cursors: X1 - X2 - X3 - X4
{
u8 input = m_cursx->read();
if (m_rotate) // reorient controls if the console is rotated
{
if (input & 0x01) value |= 0x02;
if (input & 0x02) value |= 0x04;
if (input & 0x04) value |= 0x08;
if (input & 0x08) value |= 0x01;
}
else
value = value | input;
}
break;
case 0x40: // Read buttons: START - A - B
value = value | m_buttons->read();
break;
}
break;
case 0xc0:
case 0xc1:
case 0xc2:
case 0xc3:
case 0xc4: // Cartridge EEPROM data
case 0xc5: // Cartridge EEPROM data
case 0xc6:
case 0xc7:
case 0xc8:
case 0xc9:
case 0xca:
case 0xcb: // RTC data
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
value = m_cart->read_io(offset & 0x0f);
break;
}
return value;
}
void wswan_state::port_w(offs_t offset, u8 data)
{
address_space &mem = m_maincpu->space(AS_PROGRAM);
logerror("PC=%X: port write %02X <- %02X\n", m_maincpu->pc(), offset, data);
if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0))
{
m_vdp->reg_w(offset, data);
return;
}
switch (offset)
{
case 0x40: // DMA source address (low)
case 0x41: // DMA source address (high)
case 0x42: // DMA source bank
case 0x43: // DMA destination bank
case 0x44: // DMA destination address (low)
case 0x45: // DMA destination address (high)
case 0x46: // Size of copied data (low)
case 0x47: // Size of copied data (high)
break;
case 0x48: // DMA control
// Bit 0-6 - Unknown
// Bit 7 - DMA stop/start
if (data & 0x80)
{
u32 src, dst;
u16 length;
src = m_ws_portram[0x40] + (m_ws_portram[0x41] << 8) + (m_ws_portram[0x42] << 16);
dst = m_ws_portram[0x44] + (m_ws_portram[0x45] << 8) + (m_ws_portram[0x43] << 16);
length = m_ws_portram[0x46] + (m_ws_portram[0x47] << 8);
for ( ; length > 0; length--)
{
mem.write_byte(dst, mem.read_byte(src));
src++;
dst++;
}
#ifdef MAME_DEBUG
logerror("DMA src:%X dst:%X length:%d\n", src, dst, length);
#endif
m_ws_portram[0x40] = src & 0xff;
m_ws_portram[0x41] = (src >> 8) & 0xff;
m_ws_portram[0x44] = dst & 0xff;
m_ws_portram[0x45] = (dst >> 8) & 0xff;
m_ws_portram[0x46] = length & 0xff;
m_ws_portram[0x47] = (length >> 8) & 0xff;
data &= 0x7f;
}
break;
case 0x4a: // Sound DMA source address (low)
m_sound_dma.source = (m_sound_dma.source & 0x0fff00) | data;
break;
case 0x4b: // Sound DMA source address (high)
m_sound_dma.source = (m_sound_dma.source & 0x0f00ff) | (data << 8);
break;
case 0x4c: // Sound DMA source memory segment
// Bit 0-3 - Sound DMA source address segment
// Bit 4-7 - Unknown
m_sound_dma.source = (m_sound_dma.source & 0xffff) | ((data & 0x0f) << 16);
break;
case 0x4d: // Unknown
break;
case 0x4e: // Sound DMA transfer size (low)
m_sound_dma.size = (m_sound_dma.size & 0xff00) | data;
break;
case 0x4f: // Sound DMA transfer size (high)
m_sound_dma.size = (m_sound_dma.size & 0xff) | (data << 8);
break;
case 0x50: // Unknown
case 0x51: // Unknown
break;
case 0x52: // Sound DMA start/stop
// Bit 0-6 - Unknown
// Bit 7 - Sound DMA stop/start
m_sound_dma.enable = data;
break;
case 0x60:
m_vdp->reg_w(offset, data);
break;
case 0x80: // Audio 1 freq (lo)
case 0x81: // Audio 1 freq (hi)
case 0x82: // Audio 2 freq (lo)
case 0x83: // Audio 2 freq (hi)
case 0x84: // Audio 3 freq (lo)
case 0x85: // Audio 3 freq (hi)
case 0x86: // Audio 4 freq (lo)
case 0x87: // Audio 4 freq (hi)
case 0x88: // Audio 1 volume
// Bit 0-3 - Right volume audio channel 1
// Bit 4-7 - Left volume audio channel 1
case 0x89: // Audio 2 volume
// Bit 0-3 - Right volume audio channel 2
// Bit 4-7 - Left volume audio channel 2
case 0x8a: // Audio 3 volume
// Bit 0-3 - Right volume audio channel 3
// Bit 4-7 - Left volume audio channel 3
case 0x8b: // Audio 4 volume
// Bit 0-3 - Right volume audio channel 4
// Bit 4-7 - Left volume audio channel 4
case 0x8c: // Sweep step
case 0x8d: // Sweep time
case 0x8e: // Noise control
// Bit 0-2 - Noise generator type
// Bit 3 - Reset
// Bit 4 - Enable
// Bit 5-7 - Unknown
case 0x8f: // Sample location
// Bit 0-7 - Sample address location 0 00xxxxxx xx000000
case 0x90: // Audio control
// Bit 0 - Audio 1 enable
// Bit 1 - Audio 2 enable
// Bit 2 - Audio 3 enable
// Bit 3 - Audio 4 enable
// Bit 4 - Unknown
// Bit 5 - Audio 2 voice mode enable
// Bit 6 - Audio 3 sweep mode enable
// Bit 7 - Audio 4 noise mode enable
case 0x91: // Audio output
// Bit 0 - Mono select
// Bit 1-2 - Output volume
// Bit 3 - External stereo
// Bit 4-6 - Unknown
// Bit 7 - External speaker (Read-only, set by hardware)
case 0x92: // Noise counter shift register (lo)
case 0x93: // Noise counter shift register (hi)
// Bit 0-6 - Noise counter shift register bit 8-14
// bit 7 - Unknown
case 0x94: // Master volume
// Bit 0-3 - Master volume
// Bit 4-7 - Unknown
m_sound->port_w(offset, data);
break;
case 0x9E: // WSC volume setting (0, 1, 2, 3)
break;
case 0xa0: // Hardware type/system control
// Bit 0 - Enable cartridge slot and/or disable bios
// Bit 1 - Hardware type: 0 = WS, 1 = WSC
// Bit 2 - Unknown, written during boot
// Bit 3 - Unknown, written during boot
// Bit 4-6 - Unknown
// Bit 7 - Unknown, read during boot
if ((data & 0x01) && !m_bios_disabled)
m_bios_disabled = 1;
break;
case 0xb0: // Interrupt base vector
break;
case 0xb1: // Communication byte
break;
case 0xb2: // Interrupt enable
// Bit 0 - Serial transmit interrupt enable
// Bit 1 - Key press interrupt enable
// Bit 2 - RTC alarm interrupt enable
// Bit 3 - Serial receive interrupt enable
// Bit 4 - Drawing line detection interrupt enable
// Bit 5 - VBlank timer interrupt enable
// Bit 6 - VBlank interrupt enable
// Bit 7 - HBlank timer interrupt enable
break;
case 0xb3: // serial communication control
// Bit 0 - Receive complete
// Bit 1 - Error
// Bit 2 - Send complete
// Bit 3-4 - Unknown
// Bit 5 - Send data interrupt generation
// Bit 6 - Connection speed: 0 = 9600 bps, 1 = 38400 bps
// Bit 7 - Receive data interrupt generation
m_ws_portram[0xb1] = 0xff;
if (data & 0x80)
{
// m_ws_portram[0xb1] = 0x00;
data |= 0x04;
}
if (data & 0x20)
{
// data |= 0x01;
}
break;
case 0xb5: // Read controls
// Bit 0-3 - Current state of input lines (read-only)
// Bit 4-6 - Select line of inputs to read
// 001 - Read Y cursors
// 010 - Read X cursors
// 100 - Read START,A,B buttons
// Bit 7 - Unknown
break;
case 0xb6: // Interrupt acknowledge
// Bit 0 - Serial transmit interrupt acknowledge
// Bit 1 - Key press interrupt acknowledge
// Bit 2 - RTC alarm interrupt acknowledge
// Bit 3 - Serial receive interrupt acknowledge
// Bit 4 - Drawing line detection interrupt acknowledge
// Bit 5 - VBlank timer interrupt acknowledge
// Bit 6 - VBlank interrupt acknowledge
// Bit 7 - HBlank timer interrupt acknowledge
clear_irq_line(data);
data = m_ws_portram[0xb6];
break;
case 0xba: // Internal EEPROM data (low)
case 0xbb: // Internal EEPROM data (high)
break;
case 0xbc: // Internal EEPROM address (low)
// (WS) Bit 0-5 = Internal EEPROM address
// (WSC) Bit 0-7 - Internal EEPROM address bit 1-8
case 0xbd: // Internal EEPROM address (high)
// (WSC) Bit 0 - Internal EEPROM address bit 9(?)
// Bit 1-7 - Unknown
break;
case 0xbe: // Internal EEPROM command/status
// Bit 0 - Read complete (read only)
// Bit 1 - Write complete (read only)
// Bit 2-3 - Unknown
// Bit 4 - Read
// Bit 5 - Write
// Bit 6 - Protect
// Bit 7 - Initialize
if (data & 0x20)
{
u16 addr = get_internal_eeprom_address();
m_internal_eeprom[addr] = m_ws_portram[0xba];
m_internal_eeprom[addr + 1] = m_ws_portram[0xbb];
data |= 0x02;
}
else if ( data & 0x10 )
{
u16 addr = get_internal_eeprom_address();
m_ws_portram[0xba] = m_internal_eeprom[addr];
m_ws_portram[0xbb] = m_internal_eeprom[addr + 1];
data |= 0x01;
}
else
{
logerror( "Unsupported internal EEPROM command: %X\n", data );
}
break;
case 0xc0: // ROM bank $40000-$fffff
case 0xc1: // SRAM bank
case 0xc2: // ROM bank $20000-$2ffff
case 0xc3: // ROM bank $30000-$3ffff
case 0xc4:
case 0xc5:
case 0xc6: // EEPROM address / command
case 0xc7: // EEPROM address / command
case 0xc8: // EEPROM command
case 0xc9:
case 0xca: // RTC command
case 0xcb: // RTC data
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
m_cart->write_io(offset & 0x0f, data);
break;
default:
logerror( "Write to unsupported port: %X - %X\n", offset, data );
break;
}
// Update the port value
m_ws_portram[offset] = data;
}
u16 wswan_state::get_internal_eeprom_address() {
return (m_ws_portram[0xbc] & 0x3f) << 1;
}
u16 wscolor_state::get_internal_eeprom_address() {
return (((m_ws_portram[0xbd] << 8) | m_ws_portram[0xbc]) & 0x1FF) << 1;
}
/***************************************************************************
Game driver(s)
***************************************************************************/
ROM_START( wswan )
ROM_REGION( 0x100000, "maincpu", ROMREGION_ERASEFF )
// ROM_LOAD( "ws_bios.bin", 0x0000, 0x0001, NO_DUMP )
ROM_START(wswan)
ROM_REGION(0x1000, "maincpu", 0)
ROM_LOAD("boot.rom", 0x0000, 0x1000, CRC(7f35f890) SHA1(4015bcacea76bb0b5bbdb13c5358f7e1abb986a1))
ROM_REGION(0x80, "nvram", 0)
// Need a dump from an original new unit
// Empty file containing just the name 'WONDERSAN'
ROM_LOAD("internal_eeprom.ws", 0x00, 0x80, BAD_DUMP CRC(b1dff316) SHA1(7b76c3d59c9add9501f95e8bfc34427773fcbd28))
ROM_END
ROM_START( wscolor )
ROM_REGION( 0x100000, "maincpu", ROMREGION_ERASEFF )
// ROM_LOAD( "wsc_bios.bin", 0x0000, 0x0001, NO_DUMP )
ROM_START(wscolor)
ROM_REGION(0x2000, "maincpu", 0)
ROM_LOAD("boot.rom", 0x0000, 0x2000, CRC(cb06d9c3) SHA1(c5ad0b8af45d762662a69f50b64161b9c8919efb))
ROM_REGION(0x800, "nvram", 0)
// Need a dump from an original new unit
// Empty file containing just the name 'WONDERSAN'
ROM_LOAD("internal_eeprom.wsc", 0x000, 0x800, BAD_DUMP CRC(9e29725c) SHA1(a903c2cb5f4bb94b67326ff87a2d91605dceffff))
ROM_END
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME

View File

@ -1,120 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
/*****************************************************************************
*
* includes/wswan.h
*
****************************************************************************/
#ifndef MAME_INCLUDES_WSWAN_H
#define MAME_INCLUDES_WSWAN_H
#pragma once
#define WSWAN_TYPE_MONO 0
#define WSWAN_TYPE_COLOR 1
#define INTERNAL_EEPROM_SIZE 1024
#include "cpu/v30mz/v30mz.h"
#include "machine/nvram.h"
#include "audio/wswan.h"
#include "video/wswan.h"
#include "bus/wswan/slot.h"
#include "bus/wswan/rom.h"
#include "emupal.h"
class wswan_state : public driver_device
{
public:
wswan_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_vdp(*this, "vdp"),
m_sound(*this, "custom"),
m_cart(*this, "cartslot"),
m_cursx(*this, "CURSX"),
m_cursy(*this, "CURSY"),
m_buttons(*this, "BUTTONS")
{ }
void wswan(machine_config &config);
protected:
/* Interrupt flags */
static const uint8_t WSWAN_IFLAG_STX = 0x01;
static const uint8_t WSWAN_IFLAG_KEY = 0x02;
static const uint8_t WSWAN_IFLAG_RTC = 0x04;
static const uint8_t WSWAN_IFLAG_SRX = 0x08;
static const uint8_t WSWAN_IFLAG_LCMP = 0x10;
static const uint8_t WSWAN_IFLAG_VBLTMR = 0x20;
static const uint8_t WSWAN_IFLAG_VBL = 0x40;
static const uint8_t WSWAN_IFLAG_HBLTMR = 0x80;
/* Interrupts */
static const uint8_t WSWAN_INT_STX = 0;
static const uint8_t WSWAN_INT_KEY = 1;
static const uint8_t WSWAN_INT_RTC = 2;
static const uint8_t WSWAN_INT_SRX = 3;
static const uint8_t WSWAN_INT_LCMP = 4;
static const uint8_t WSWAN_INT_VBLTMR = 5;
static const uint8_t WSWAN_INT_VBL = 6;
static const uint8_t WSWAN_INT_HBLTMR = 7;
struct SoundDMA
{
uint32_t source; /* Source address */
uint16_t size; /* Size */
uint8_t enable; /* Enabled */
};
required_device<cpu_device> m_maincpu;
required_device<wswan_video_device> m_vdp;
required_device<wswan_sound_device> m_sound;
required_device<ws_cart_slot_device> m_cart;
uint8_t m_ws_portram[256];
uint8_t m_internal_eeprom[INTERNAL_EEPROM_SIZE];
uint8_t m_system_type;
SoundDMA m_sound_dma;
std::unique_ptr<uint8_t[]> m_ws_bios_bank;
uint8_t m_bios_disabled;
uint8_t m_rotate;
required_ioport m_cursx;
required_ioport m_cursy;
required_ioport m_buttons;
uint8_t bios_r(offs_t offset);
uint8_t port_r(offs_t offset);
void port_w(offs_t offset, uint8_t data);
void set_irq_line(int irq);
void dma_sound_cb();
void common_start();
virtual void machine_start() override;
virtual void machine_reset() override;
void wswan_palette(palette_device &palette) const;
void wswan_io(address_map &map);
void wswan_mem(address_map &map);
void wswan_snd(address_map &map);
void register_save();
void handle_irqs();
void clear_irq_line(int irq);
};
class wscolor_state : public wswan_state
{
public:
using wswan_state::wswan_state;
void wscolor(machine_config &config);
protected:
virtual void machine_start() override;
void wscolor_mem(address_map &map);
void wscolor_palette(palette_device &palette) const;
};
#endif // MAME_INCLUDES_WSWAN_H

View File

@ -1,664 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Anthony Kruize,Wilbert Pol
/***************************************************************************
wswan.c
Machine file to handle emulation of the Bandai WonderSwan.
Anthony Kruize
Wilbert Pol
TODO:
SRAM sizes should be in kbit instead of kbytes(?). This raises a few
interesting issues:
- mirror of smaller <64KBYTE/512kbit sram sizes
- banking when using 1M or 2M sram sizes
***************************************************************************/
#include "emu.h"
#include "includes/wswan.h"
#include "render.h"
#define INTERNAL_EEPROM_SIZE 1024
enum enum_system { TYPE_WSWAN=0, TYPE_WSC };
static const uint8_t ws_portram_init[256] =
{
0x00, 0x00, 0x00/*?*/, 0xbb, 0x00, 0x00, 0x00, 0x26, 0xfe, 0xde, 0xf9, 0xfb, 0xdb, 0xd7, 0x7f, 0xf5,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9e, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x99, 0xfd, 0xb7, 0xdf,
0x30, 0x57, 0x75, 0x76, 0x15, 0x73, 0x70/*77?*/, 0x77, 0x20, 0x75, 0x50, 0x36, 0x70, 0x67, 0x50, 0x77,
0x57, 0x54, 0x75, 0x77, 0x75, 0x17, 0x37, 0x73, 0x50, 0x57, 0x60, 0x77, 0x70, 0x77, 0x10, 0x73,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
0x87, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x4f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xdb, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x42, 0x00, 0x83, 0x00,
0x2f, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1,
0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1
};
/*
Some fake bios code to initialize some registers and set up some things on the wonderswan.
The code from f:ffe0 which gets copied to 0:0400 is taken from a wonderswan crystal's initial
memory settings. Lacking real bios dumps we will use this....
The setting of SP to 2000h is what's needed to get Wonderswan Colloseum to boot.
f000:ffc0
FC cld
BC 00 20 mov sp,2000h
68 00 00 push 0000h
07 pop es
68 00 F0 push F000h
1F pop ds
BF 00 04 mov di,0400h
BE E0 FF mov si,FFE0h
B9 10 00 mov cx,0010h
F3 A4 rep movsb
B0 2F mov al,2Fh
E6 C0 out al,C0h
EA 00 04 00 00 jmp 0000:0400
f000:ffe0
E4 A0 in al, A0h
0C 01 or al,01h
E6 A0 out al,A0h
EA 00 00 FF FF jmp FFFFh:0000h
*/
static const uint8_t ws_fake_bios_code[] = {
0xfc, 0xbc, 0x00, 0x20, 0x68, 0x00, 0x00, 0x07, 0x68, 0x00, 0xf0, 0x1f, 0xbf, 0x00, 0x04, 0xbe,
0xe0, 0xff, 0xb9, 0x10, 0x00, 0xf3, 0xa4, 0xb0, 0x2f, 0xe6, 0xc0, 0xea, 0x00, 0x04, 0x00, 0x00,
0xe4, 0xa0, 0x0c, 0x01, 0xe6, 0xa0, 0xea, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0xea, 0xc0, 0xff, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
void wswan_state::handle_irqs()
{
if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_HBLTMR)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_HBLTMR); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBL)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBL); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_VBLTMR)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_VBLTMR); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_LCMP)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_LCMP); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_SRX)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_SRX); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_RTC)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_RTC); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_KEY)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_KEY); // V30MZ
}
else if (m_ws_portram[0xb2] & m_ws_portram[0xb6] & WSWAN_IFLAG_STX)
{
m_maincpu->set_input_line_and_vector(0, HOLD_LINE, m_ws_portram[0xb0] + WSWAN_INT_STX); // V30MZ
}
else
{
m_maincpu->set_input_line(0, CLEAR_LINE);
}
}
void wswan_state::set_irq_line(int irq)
{
if (m_ws_portram[0xb2] & irq)
{
m_ws_portram[0xb6] |= irq;
handle_irqs();
}
}
void wswan_state::dma_sound_cb()
{
if ((m_sound_dma.enable & 0x88) == 0x80)
{
address_space &space = m_maincpu->space(AS_PROGRAM);
/* TODO: Output sound DMA byte */
port_w(0x89, space.read_byte(m_sound_dma.source));
m_sound_dma.size--;
m_sound_dma.source = (m_sound_dma.source + 1) & 0x0fffff;
if (m_sound_dma.size == 0)
{
m_sound_dma.enable &= 0x7F;
}
}
}
void wswan_state::clear_irq_line(int irq)
{
m_ws_portram[0xb6] &= ~irq;
handle_irqs();
}
void wswan_state::register_save()
{
save_item(NAME(m_ws_portram));
save_item(NAME(m_internal_eeprom));
save_item(NAME(m_bios_disabled));
save_item(NAME(m_rotate));
save_item(NAME(m_sound_dma.source));
save_item(NAME(m_sound_dma.size));
save_item(NAME(m_sound_dma.enable));
if (m_cart->exists())
m_cart->save_nvram();
}
void wswan_state::common_start()
{
m_ws_bios_bank = std::make_unique<uint8_t[]>(0x10000);
memcpy(m_ws_bios_bank.get() + 0xffc0, ws_fake_bios_code, 0x40);
register_save();
subdevice<nvram_device>("nvram")->set_base(m_internal_eeprom, INTERNAL_EEPROM_SIZE);
if (m_cart->exists())
{
// ROM
m_maincpu->space(AS_PROGRAM).install_read_handler(0x20000, 0x2ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom20)));
m_maincpu->space(AS_PROGRAM).install_read_handler(0x30000, 0x3ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom30)));
m_maincpu->space(AS_PROGRAM).install_read_handler(0x40000, 0xeffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_rom40)));
// SRAM
if (m_cart->get_type() == WS_SRAM)
{
m_maincpu->space(AS_PROGRAM).install_read_handler(0x10000, 0x1ffff, read8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::read_ram)));
m_maincpu->space(AS_PROGRAM).install_write_handler(0x10000, 0x1ffff, write8sm_delegate(*m_cart, FUNC(ws_cart_slot_device::write_ram)));
}
}
}
void wswan_state::machine_start()
{
common_start();
m_system_type = TYPE_WSWAN;
}
void wscolor_state::machine_start()
{
common_start();
m_system_type = TYPE_WSC;
}
void wswan_state::machine_reset()
{
m_bios_disabled = 0;
if (m_cart->exists())
m_rotate = m_cart->get_is_rotated();
else
m_rotate = 0;
/* Intialize ports */
memcpy(m_ws_portram, ws_portram_init, 256);
render_target *target = machine().render().first_target();
target->set_view(m_rotate);
/* Initialize sound DMA */
memset(&m_sound_dma, 0, sizeof(m_sound_dma));
}
uint8_t wswan_state::bios_r(offs_t offset)
{
if (!m_bios_disabled)
return m_ws_bios_bank[offset];
else
return m_cart->read_rom40(offset + 0xb0000);
}
uint8_t wswan_state::port_r(offs_t offset)
{
uint8_t value = m_ws_portram[offset];
if (offset != 2)
logerror("PC=%X: port read %02X\n", m_maincpu->pc(), offset);
if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0))
return m_vdp->reg_r(offset);
switch (offset)
{
case 0x4a: // Sound DMA source address (low)
value = m_sound_dma.source & 0xff;
break;
case 0x4b: // Sound DMA source address (high)
value = (m_sound_dma.source >> 8) & 0xff;
break;
case 0x4c: // Sound DMA source memory segment
value = (m_sound_dma.source >> 16) & 0xff;
break;
case 0x4e: // Sound DMA transfer size (low)
value = m_sound_dma.size & 0xff;
break;
case 0x4f: // Sound DMA transfer size (high)
value = (m_sound_dma.size >> 8) & 0xff;
break;
case 0x52: // Sound DMA start/stop
value = m_sound_dma.enable;
break;
case 0x60:
value = m_vdp->reg_r(offset);
break;
case 0xa0: // Hardware type
// Bit 0 - Disable/enable Bios
// Bit 1 - Determine mono/color
// Bit 2 - Determine color/crystal
value = value & ~ 0x02;
if (m_system_type == TYPE_WSC)
value |= 2;
break;
case 0xc0:
case 0xc1:
case 0xc2:
case 0xc3:
case 0xc4: // EEPROM data
case 0xc5: // EEPROM data
case 0xc6:
case 0xc7:
case 0xc8:
case 0xc9:
case 0xca:
case 0xcb: // RTC data
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
value = m_cart->read_io(offset & 0x0f);
break;
}
return value;
}
void wswan_state::port_w(offs_t offset, uint8_t data)
{
address_space &mem = m_maincpu->space(AS_PROGRAM);
uint8_t input;
logerror("PC=%X: port write %02X <- %02X\n", m_maincpu->pc(), offset, data);
if (offset < 0x40 || (offset >= 0xa1 && offset < 0xb0))
{
m_vdp->reg_w(offset, data);
return;
}
switch (offset)
{
case 0x40: /* DMA source address (low)
Bit 0-7 - DMA source address bit 0-7
*/
case 0x41: /* DMA source address (high)
Bit 0-7 - DMA source address bit 8-15
*/
case 0x42: /* DMA source bank
Bit 0-7 - DMA source bank number
*/
case 0x43: /* DMA destination bank
Bit 0-7 - DMA destination bank number
*/
case 0x44: /* DMA destination address (low)
Bit 0-7 - DMA destination address bit 0-7
*/
case 0x45: /* DMA destination address (high)
Bit 0-7 - DMA destination address bit 8-15
*/
case 0x46: /* Size of copied data (low)
Bit 0-7 - DMA size bit 0-7
*/
case 0x47: /* Size of copied data (high)
Bit 0-7 - DMA size bit 8-15
*/
break;
case 0x48: /* DMA control
Bit 0-6 - Unknown
Bit 7 - DMA stop/start
*/
if (data & 0x80)
{
uint32_t src, dst;
uint16_t length;
src = m_ws_portram[0x40] + (m_ws_portram[0x41] << 8) + (m_ws_portram[0x42] << 16);
dst = m_ws_portram[0x44] + (m_ws_portram[0x45] << 8) + (m_ws_portram[0x43] << 16);
length = m_ws_portram[0x46] + (m_ws_portram[0x47] << 8);
for ( ; length > 0; length--)
{
mem.write_byte(dst, mem.read_byte(src));
src++;
dst++;
}
#ifdef MAME_DEBUG
logerror("DMA src:%X dst:%X length:%d\n", src, dst, length);
#endif
m_ws_portram[0x40] = src & 0xff;
m_ws_portram[0x41] = (src >> 8) & 0xff;
m_ws_portram[0x44] = dst & 0xff;
m_ws_portram[0x45] = (dst >> 8) & 0xff;
m_ws_portram[0x46] = length & 0xff;
m_ws_portram[0x47] = (length >> 8) & 0xff;
data &= 0x7f;
}
break;
case 0x4a: /* Sound DMA source address (low)
Bit 0-7 - Sound DMA source address bit 0-7
*/
m_sound_dma.source = (m_sound_dma.source & 0x0fff00) | data;
break;
case 0x4b: /* Sound DMA source address (high)
Bit 0-7 - Sound DMA source address bit 8-15
*/
m_sound_dma.source = (m_sound_dma.source & 0x0f00ff) | (data << 8);
break;
case 0x4c: /* Sound DMA source memory segment
Bit 0-3 - Sound DMA source address segment
Bit 4-7 - Unknown
*/
m_sound_dma.source = (m_sound_dma.source & 0xffff) | ((data & 0x0f) << 16);
break;
case 0x4d: /* Unknown */
break;
case 0x4e: /* Sound DMA transfer size (low)
Bit 0-7 - Sound DMA transfer size bit 0-7
*/
m_sound_dma.size = (m_sound_dma.size & 0xff00) | data;
break;
case 0x4f: /* Sound DMA transfer size (high)
Bit 0-7 - Sound DMA transfer size bit 8-15
*/
m_sound_dma.size = (m_sound_dma.size & 0xff) | (data << 8);
break;
case 0x50: /* Unknown */
case 0x51: /* Unknown */
break;
case 0x52: /* Sound DMA start/stop
Bit 0-6 - Unknown
Bit 7 - Sound DMA stop/start
*/
m_sound_dma.enable = data;
break;
case 0x60:
m_vdp->reg_w(offset, data);
break;
case 0x80: /* Audio 1 freq (lo)
Bit 0-7 - Audio channel 1 frequency bit 0-7
*/
case 0x81: /* Audio 1 freq (hi)
Bit 0-7 - Audio channel 1 frequency bit 8-15
*/
case 0x82: /* Audio 2 freq (lo)
Bit 0-7 - Audio channel 2 frequency bit 0-7
*/
case 0x83: /* Audio 2 freq (hi)
Bit 0-7 - Audio channel 2 frequency bit 8-15
*/
case 0x84: /* Audio 3 freq (lo)
Bit 0-7 - Audio channel 3 frequency bit 0-7
*/
case 0x85: /* Audio 3 freq (hi)
Bit 0-7 - Audio channel 3 frequency bit 8-15
*/
case 0x86: /* Audio 4 freq (lo)
Bit 0-7 - Audio channel 4 frequency bit 0-7
*/
case 0x87: /* Audio 4 freq (hi)
Bit 0-7 - Audio channel 4 frequency bit 8-15
*/
case 0x88: /* Audio 1 volume
Bit 0-3 - Right volume audio channel 1
Bit 4-7 - Left volume audio channel 1
*/
case 0x89: /* Audio 2 volume
Bit 0-3 - Right volume audio channel 2
Bit 4-7 - Left volume audio channel 2
*/
case 0x8a: /* Audio 3 volume
Bit 0-3 - Right volume audio channel 3
Bit 4-7 - Left volume audio channel 3
*/
case 0x8b: /* Audio 4 volume
Bit 0-3 - Right volume audio channel 4
Bit 4-7 - Left volume audio channel 4
*/
case 0x8c: /* Sweep step
Bit 0-7 - Sweep step
*/
case 0x8d: /* Sweep time
Bit 0-7 - Sweep time
*/
case 0x8e: /* Noise control
Bit 0-2 - Noise generator type
Bit 3 - Reset
Bit 4 - Enable
Bit 5-7 - Unknown
*/
case 0x8f: /* Sample location
Bit 0-7 - Sample address location 0 00xxxxxx xx000000
*/
case 0x90: /* Audio control
Bit 0 - Audio 1 enable
Bit 1 - Audio 2 enable
Bit 2 - Audio 3 enable
Bit 3 - Audio 4 enable
Bit 4 - Unknown
Bit 5 - Audio 2 voice mode enable
Bit 6 - Audio 3 sweep mode enable
Bit 7 - Audio 4 noise mode enable
*/
case 0x91: /* Audio output
Bit 0 - Mono select
Bit 1-2 - Output volume
Bit 3 - External stereo
Bit 4-6 - Unknown
Bit 7 - External speaker (Read-only, set by hardware)
*/
case 0x92: /* Noise counter shift register (lo)
Bit 0-7 - Noise counter shift register bit 0-7
*/
case 0x93: /* Noise counter shift register (hi)
Bit 0-6 - Noise counter shift register bit 8-14
bit 7 - Unknown
*/
case 0x94: /* Master volume
Bit 0-3 - Master volume
Bit 4-7 - Unknown
*/
m_sound->port_w(offset, data);
break;
case 0xa0: /* Hardware type - this is probably read only
Bit 0 - Enable cartridge slot and/or disable bios
Bit 1 - Hardware type: 0 = WS, 1 = WSC
Bit 2-7 - Unknown
*/
if ((data & 0x01) && !m_bios_disabled)
m_bios_disabled = 1;
break;
case 0xb0: /* Interrupt base vector
Bit 0-7 - Interrupt base vector
*/
break;
case 0xb1: /* Communication byte
Bit 0-7 - Communication byte
*/
break;
case 0xb2: /* Interrupt enable
Bit 0 - Serial transmit interrupt enable
Bit 1 - Key press interrupt enable
Bit 2 - RTC alarm interrupt enable
Bit 3 - Serial receive interrupt enable
Bit 4 - Drawing line detection interrupt enable
Bit 5 - VBlank timer interrupt enable
Bit 6 - VBlank interrupt enable
Bit 7 - HBlank timer interrupt enable
*/
break;
case 0xb3: /* serial communication control
Bit 0 - Receive complete
Bit 1 - Error
Bit 2 - Send complete
Bit 3-4 - Unknown
Bit 5 - Send data interrupt generation
Bit 6 - Connection speed: 0 = 9600 bps, 1 = 38400 bps
bit 7 - Receive data interrupt generation
*/
// data |= 0x02;
m_ws_portram[0xb1] = 0xff;
if (data & 0x80)
{
// m_ws_portram[0xb1] = 0x00;
data |= 0x04;
}
if (data & 0x20)
{
// data |= 0x01;
}
break;
case 0xb5: /* Read controls
Bit 0-3 - Current state of input lines (read-only)
Bit 4-6 - Select line of inputs to read
001 - Read Y cursors
010 - Read X cursors
100 - Read START,A,B buttons
Bit 7 - Unknown
*/
data = data & 0xf0;
switch (data)
{
case 0x10: /* Read Y cursors: Y1 - Y2 - Y3 - Y4 */
input = m_cursy->read();
if (m_rotate) // reorient controls if the console is rotated
{
if (input & 0x01) data |= 0x02;
if (input & 0x02) data |= 0x04;
if (input & 0x04) data |= 0x08;
if (input & 0x08) data |= 0x01;
}
else
data = data | input;
break;
case 0x20: /* Read X cursors: X1 - X2 - X3 - X4 */
input = m_cursx->read();
if (m_rotate) // reorient controls if the console is rotated
{
if (input & 0x01) data |= 0x02;
if (input & 0x02) data |= 0x04;
if (input & 0x04) data |= 0x08;
if (input & 0x08) data |= 0x01;
}
else
data = data | input;
break;
case 0x40: /* Read buttons: START - A - B */
data = data | m_buttons->read();
break;
}
break;
case 0xb6: /* Interrupt acknowledge
Bit 0 - Serial transmit interrupt acknowledge
Bit 1 - Key press interrupt acknowledge
Bit 2 - RTC alarm interrupt acknowledge
Bit 3 - Serial receive interrupt acknowledge
Bit 4 - Drawing line detection interrupt acknowledge
Bit 5 - VBlank timer interrupt acknowledge
Bit 6 - VBlank interrupt acknowledge
Bit 7 - HBlank timer interrupt acknowledge
*/
clear_irq_line(data);
data = m_ws_portram[0xb6];
break;
case 0xba: /* Internal EEPROM data (low)
Bit 0-7 - Internal EEPROM data transfer bit 0-7
*/
case 0xbb: /* Internal EEPROM data (high)
Bit 0-7 - Internal EEPROM data transfer bit 8-15
*/
break;
case 0xbc: /* Internal EEPROM address (low)
Bit 0-7 - Internal EEPROM address bit 1-8
*/
case 0xbd: /* Internal EEPROM address (high)
Bit 0 - Internal EEPROM address bit 9(?)
Bit 1-7 - Unknown
Only 1KByte internal EEPROM??
*/
break;
case 0xbe: /* Internal EEPROM command
Bit 0 - Read complete (read only)
Bit 1 - Write complete (read only)
Bit 2-3 - Unknown
Bit 4 - Read
Bit 5 - Write
Bit 6 - Protect
Bit 7 - Initialize
*/
if (data & 0x20)
{
uint16_t addr = ( ( ( m_ws_portram[0xbd] << 8 ) | m_ws_portram[0xbc] ) << 1 ) & 0x1FF;
m_internal_eeprom[ addr ] = m_ws_portram[0xba];
m_internal_eeprom[ addr + 1 ] = m_ws_portram[0xbb];
data |= 0x02;
}
else if ( data & 0x10 )
{
uint16_t addr = ( ( ( m_ws_portram[0xbd] << 8 ) | m_ws_portram[0xbc] ) << 1 ) & 0x1FF;
m_ws_portram[0xba] = m_internal_eeprom[ addr ];
m_ws_portram[0xbb] = m_internal_eeprom[ addr + 1];
data |= 0x01;
}
else
{
logerror( "Unsupported internal EEPROM command: %X\n", data );
}
break;
case 0xc0: // ROM bank $40000-$fffff
case 0xc1: // SRAM bank
case 0xc2: // ROM bank $20000-$2ffff
case 0xc3: // ROM bank $30000-$3ffff
case 0xc4:
case 0xc5:
case 0xc6: // EEPROM address / command
case 0xc7: // EEPROM address / command
case 0xc8: // EEPROM command
case 0xc9:
case 0xca: // RTC command
case 0xcb: // RTC data
case 0xcc:
case 0xcd:
case 0xce:
case 0xcf:
m_cart->write_io(offset & 0x0f, data);
break;
default:
logerror( "Write to unsupported port: %X - %X\n", offset, data );
break;
}
/* Update the port value */
m_ws_portram[offset] = data;
}

View File

@ -9,7 +9,8 @@
TODO:
- remove the redundant parts of m_regs
- split the Color VDP from the Mono VDP?
- split the Color VDP from the Mono VDP
- Add support for WSC high/low contrast (register 14, bit 1)
***************************************************************************/
@ -804,8 +805,7 @@ void wswan_video_device::refresh_scanline()
rectangle rec(0, WSWAN_X_PIXELS, m_current_line, m_current_line);
if (m_lcd_control)
{
/* Not sure if these background color checks and settings are correct */
if (m_color_mode && m_colors_16)
if (m_color_mode)
m_bitmap.fill(m_pal[m_bg_control >> 4][m_bg_control & 0x0f], rec);
else
m_bitmap.fill(m_main_palette[m_bg_control & 0x07], rec);
@ -1007,7 +1007,8 @@ void wswan_video_device::reg_w(offs_t offset, uint8_t data)
break;
case 0x14: // LCD control
// Bit 0 - LCD enable
// Bit 1-7 - Unknown
// Bit 1 - WSC only, brightness low/high
// Bit 2-7 - Unknown
m_lcd_control = data;
break;
case 0x15: // LCD icons

View File

@ -16,20 +16,6 @@
#pragma once
enum
{
VDP_TYPE_WSWAN = 0,
VDP_TYPE_WSC
};
#define WSWAN_X_PIXELS (28*8)
#define WSWAN_Y_PIXELS (18*8)
#define WSWAN_VIDEO_IRQ_CB_MEMBER(_name) void _name(int irq)
#define WSWAN_VIDEO_DMASND_CB_MEMBER(_name) void _name()
class wswan_video_device : public device_t, public device_video_interface
{
public:
@ -51,6 +37,15 @@ public:
uint8_t reg_r(offs_t offset);
void reg_w(offs_t offset, uint8_t data);
enum
{
VDP_TYPE_WSWAN = 0,
VDP_TYPE_WSC
};
static const u16 WSWAN_X_PIXELS = (28*8);
static const u16 WSWAN_Y_PIXELS = (18*8);
protected:
// device-level overrides
virtual void device_start() override;