diff options
Diffstat (limited to 'src/devices/bus/wswan/rom.c')
-rw-r--r-- | src/devices/bus/wswan/rom.c | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/src/devices/bus/wswan/rom.c b/src/devices/bus/wswan/rom.c new file mode 100644 index 00000000000..de57f954b8c --- /dev/null +++ b/src/devices/bus/wswan/rom.c @@ -0,0 +1,524 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/*********************************************************************************************************** + + + Bandai Wonderswan / Wonderswan Color cart emulation + + + ***********************************************************************************************************/ + + +#include "emu.h" +#include "rom.h" + +enum +{ + EEPROM_1K, EEPROM_8K, EEPROM_16K +}; + +//------------------------------------------------- +// ws_rom_device - constructor +//------------------------------------------------- + +const device_type WS_ROM_STD = &device_creator<ws_rom_device>; +const device_type WS_ROM_SRAM = &device_creator<ws_rom_sram_device>; +const device_type WS_ROM_EEPROM = &device_creator<ws_rom_eeprom_device>; + + +ws_rom_device::ws_rom_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_ws_cart_interface( mconfig, *this ) +{ +} + +ws_rom_device::ws_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, WS_ROM_STD, "Wonderswan Standard Carts", tag, owner, clock, "ws_rom", __FILE__), + device_ws_cart_interface( mconfig, *this ) +{ +} + +ws_rom_sram_device::ws_rom_sram_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ws_rom_device(mconfig, WS_ROM_SRAM, "Wonderswan Carts w/SRAM", tag, owner, clock, "ws_sram", __FILE__) +{ +} + + +ws_rom_eeprom_device::ws_rom_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ws_rom_device(mconfig, WS_ROM_EEPROM, "Wonderswan Carts w/EEPROM", tag, owner, clock, "ws_eeprom", __FILE__) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void ws_rom_device::device_start() +{ + save_item(NAME(m_base20)); + save_item(NAME(m_base30)); + save_item(NAME(m_base40)); + save_item(NAME(m_io_regs)); + + // Set up RTC timer + if (m_has_rtc) + { + rtc_timer = timer_alloc(TIMER_RTC); + rtc_timer->adjust(attotime::zero, 0, attotime::from_seconds(1)); + } + + save_item(NAME(m_rtc_setting)); + save_item(NAME(m_rtc_year)); + save_item(NAME(m_rtc_month)); + save_item(NAME(m_rtc_day)); + save_item(NAME(m_rtc_day_of_week)); + save_item(NAME(m_rtc_hour)); + save_item(NAME(m_rtc_minute)); + save_item(NAME(m_rtc_second)); + save_item(NAME(m_rtc_index)); +} + +void ws_rom_device::device_reset() +{ + m_base20 = ((0xff & m_bank_mask) << 16) & (m_rom_size - 1); + m_base30 = ((0xff & m_bank_mask) << 16) & (m_rom_size - 1); + m_base40 = (((0xf0 & m_bank_mask) | 4) << 16) & (m_rom_size - 1); + + memset(m_io_regs, 0, sizeof(m_io_regs)); + + // Initialize RTC + m_rtc_index = 0; + m_rtc_year = 0; + m_rtc_month = 0; + m_rtc_day = 0; + m_rtc_day_of_week = 0; + m_rtc_hour = 0; + m_rtc_minute = 0; + m_rtc_second = 0; + m_rtc_setting = 0xff; +} + +void ws_rom_sram_device::device_start() +{ + save_item(NAME(m_nvram_base)); + ws_rom_device::device_start(); +} + +void ws_rom_sram_device::device_reset() +{ + m_nvram_base = 0; + ws_rom_device::device_reset(); +} + +void ws_rom_eeprom_device::device_start() +{ + ws_rom_device::device_start(); + + save_item(NAME(m_eeprom_address)); + save_item(NAME(m_eeprom_command)); + save_item(NAME(m_eeprom_start)); + save_item(NAME(m_eeprom_write_enabled)); +} + +void ws_rom_eeprom_device::device_reset() +{ + m_eeprom_address = 0; + m_eeprom_command = 0; + m_eeprom_start = 0; + m_eeprom_write_enabled = 0; + switch (m_nvram.size()) + { + case 0x80: + m_eeprom_mode = EEPROM_1K; + break; + case 0x400: + m_eeprom_mode = EEPROM_8K; + break; + case 0x800: + m_eeprom_mode = EEPROM_16K; + break; + } + ws_rom_device::device_reset(); +} + + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void ws_rom_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_RTC) + { + // a second passed + m_rtc_second++; + if ((m_rtc_second & 0x0f) > 9) + m_rtc_second = (m_rtc_second & 0xf0) + 0x10; + + // check for minute passed + if (m_rtc_second >= 0x60) + { + m_rtc_second = 0; + m_rtc_minute++; + if ((m_rtc_minute & 0x0f) > 9) + m_rtc_minute = (m_rtc_minute & 0xf0) + 0x10; + } + + // check for hour passed + if (m_rtc_minute >= 0x60) + { + m_rtc_minute = 0; + m_rtc_hour++; + if ((m_rtc_hour & 0x0f) > 9) + m_rtc_hour = (m_rtc_hour & 0xf0) + 0x10; + if (m_rtc_hour == 0x12) + m_rtc_hour |= 0x80; + } + + // check for day passed + if (m_rtc_hour >= 0x24) + { + m_rtc_hour = 0; + m_rtc_day++; + } + } +} + + +/*------------------------------------------------- + mapper specific handlers + -------------------------------------------------*/ + +READ8_MEMBER(ws_rom_device::read_rom20) +{ + return m_rom[offset + m_base20]; +} + + +READ8_MEMBER(ws_rom_device::read_rom30) +{ + return m_rom[offset + m_base30]; +} + + +READ8_MEMBER(ws_rom_device::read_rom40) +{ + // we still need to mask in some cases, e.g. when game is 512K + return m_rom[(offset + m_base40) & (m_rom_size - 1)]; +} + + +READ8_MEMBER(ws_rom_device::read_io) +{ + UINT8 value = m_io_regs[offset]; + + switch (offset) + { + case 0x0b: // RTC data + if (!m_has_rtc) + break; + + if (m_io_regs[0x0a] == 0x95 && (m_rtc_index < 7)) + { + switch (m_rtc_index) + { + case 0: value = m_rtc_year; break; + case 1: value = m_rtc_month; break; + case 2: value = m_rtc_day; break; + case 3: value = m_rtc_day_of_week; break; + case 4: value = m_rtc_hour; break; + case 5: value = m_rtc_minute; break; + case 6: value = m_rtc_second; break; + } + m_rtc_index++; + } + break; + } + + return value; +} + +WRITE8_MEMBER(ws_rom_device::write_io) +{ + switch (offset) + { + case 0x00: + // Bit 0-3 - ROM bank base register for segments 3-15 + // Bit 4-7 - Unknown + data = ((data & 0x0f) << 4) | 4; + m_base40 = ((data & m_bank_mask) << 16) & (m_rom_size - 1); + break; + case 0x02: // ROM bank for segment 2 (0x20000 - 0x2ffff) + m_base20 = ((data & m_bank_mask) << 16) & (m_rom_size - 1); + break; + case 0x03: // ROM bank for segment 3 (0x30000 - 0x3ffff) + m_base30 = ((data & m_bank_mask) << 16) & (m_rom_size - 1); + break; + case 0x0a: // RTC Command + // Bit 0-4 - RTC command + // 10000 - Reset + // 10010 - Write timer settings (alarm) + // 10011 - Read timer settings (alarm) + // 10100 - Set time/date + // 10101 - Get time/date + // Bit 5-6 - Unknown + // Bit 7 - Command done (read only) + if (!m_has_rtc) + break; + + switch (data) + { + case 0x10: // Reset + m_rtc_index = 8; + m_rtc_year = 0; + m_rtc_month = 1; + m_rtc_day = 1; + m_rtc_day_of_week = 0; + m_rtc_hour = 0; + m_rtc_minute = 0; + m_rtc_second = 0; + m_rtc_setting = 0xff; + data |= 0x80; + break; + case 0x12: // Write Timer Settings (Alarm) + m_rtc_index = 8; + m_rtc_setting = m_io_regs[0x0b]; + data |= 0x80; + break; + case 0x13: // Read Timer Settings (Alarm) + m_rtc_index = 8; + m_io_regs[0x0b] = m_rtc_setting; + data |= 0x80; + break; + case 0x14: // Set Time/Date + m_rtc_year = m_io_regs[0x0b]; + m_rtc_index = 1; + data |= 0x80; + break; + case 0x15: // Get Time/Date + m_rtc_index = 0; + data |= 0x80; + m_io_regs[0x0b] = m_rtc_year; + break; + default: + logerror( "Unknown RTC command (%X) requested\n", data); + } + break; + case 0x0b: // RTC Data + if (!m_has_rtc) + break; + + if (m_io_regs[0x0a] == 0x94 && m_rtc_index < 7) + { + switch (m_rtc_index) + { + case 0: m_rtc_year = data; break; + case 1: m_rtc_month = data; break; + case 2: m_rtc_day = data; break; + case 3: m_rtc_day_of_week = data; break; + case 4: m_rtc_hour = data; break; + case 5: m_rtc_minute = data; break; + case 6: m_rtc_second = data; break; + } + m_rtc_index++; + } + break; + } + + m_io_regs[offset] = data; +} + +READ8_MEMBER(ws_rom_sram_device::read_ram) +{ + return m_nvram[m_nvram_base + offset]; +} + +WRITE8_MEMBER(ws_rom_sram_device::write_ram) +{ + m_nvram[m_nvram_base + offset] = data; +} + +WRITE8_MEMBER(ws_rom_sram_device::write_io) +{ + switch (offset) + { + case 0x01: // SRAM bank to select + m_nvram_base = (data * 0x10000) & (m_nvram.size() - 1); + default: + ws_rom_device::write_io(space, offset, data); + break; + } +} + + +READ8_MEMBER(ws_rom_eeprom_device::read_io) +{ + UINT8 value = m_io_regs[offset]; + + switch (offset) + { + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + // EEPROM reads, taken from regs + break; + default: + value = ws_rom_device::read_io(space, offset); + break; + } + + return value; +} + +WRITE8_MEMBER(ws_rom_eeprom_device::write_io) +{ + switch (offset) + { + case 0x06: /* EEPROM address lower bits port/EEPROM address and command port + 1KBit EEPROM: + Bit 0-5 - EEPROM address bit 1-6 + Bit 6-7 - Command + 00 - Extended command address bit 4-5: + 00 - Write disable + 01 - Write all + 10 - Erase all + 11 - Write enable + 01 - Write + 10 - Read + 11 - Erase + 16KBit EEPROM: + Bit 0-7 - EEPROM address bit 1-8 + */ + switch (m_eeprom_mode) + { + case EEPROM_1K: + m_eeprom_address = data & 0x3f; + m_eeprom_command = data >> 4; + if ((m_eeprom_command & 0x0c) != 0x00) + m_eeprom_command = m_eeprom_command & 0x0c; + break; + + case EEPROM_8K: + case EEPROM_16K: + m_eeprom_address = (m_eeprom_address & 0xff00) | data; + break; + + default: + logerror( "Write EEPROM address/register register C6 for unsupported EEPROM type\n" ); + break; + } + break; + + case 0x07: /* EEPROM higher bits/command bits port + 1KBit EEPROM: + Bit 0 - Start + Bit 1-7 - Unknown + 16KBit EEPROM: + Bit 0-1 - EEPROM address bit 9-10 + Bit 2-3 - Command + 00 - Extended command address bit 0-1: + 00 - Write disable + 01 - Write all + 10 - Erase all + 11 - Write enable + 01 - Write + 10 - Read + 11 - Erase + Bit 4 - Start + Bit 5-7 - Unknown + */ + switch (m_eeprom_mode) + { + case EEPROM_1K: + m_eeprom_start = data & 0x01; + break; + + case EEPROM_8K: + m_eeprom_address = ((data & 0x01) << 8) | (m_eeprom_address & 0xff); + m_eeprom_command = data & 0x0f; + if ((m_eeprom_command & 0x0c) != 0x00) + m_eeprom_command = m_eeprom_command & 0x0c; + m_eeprom_start = (data >> 4) & 0x01; + break; + + case EEPROM_16K: + m_eeprom_address = ((data & 0x03) << 8) | (m_eeprom_address & 0xff); + m_eeprom_command = data & 0x0f; + if ((m_eeprom_command & 0x0c) != 0x00) + m_eeprom_command = m_eeprom_command & 0x0c; + m_eeprom_start = (data >> 4) & 0x01; + break; + + default: + logerror( "Write EEPROM address/command register C7 for unsupported EEPROM type\n" ); + break; + } + break; + + case 0x08: /* 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 & 0x80) // Initialize + logerror("Unsupported EEPROM command 'Initialize'\n"); + + if (data & 0x40) // Protect + { + switch (m_eeprom_command) + { + case 0x00: + m_eeprom_write_enabled = 0; + data |= 0x02; + break; + case 0x03: + m_eeprom_write_enabled = 1; + data |= 0x02; + break; + default: + logerror("Unsupported 'Protect' command %X\n", m_eeprom_command); + break; + } + } + + if (data & 0x20) // Write + { + if (m_eeprom_write_enabled) + { + switch (m_eeprom_command) + { + case 0x04: + m_nvram[(m_eeprom_address << 1) + 1] = m_io_regs[0x04]; + m_nvram[m_eeprom_address << 1] = m_io_regs[0x05]; + data |= 0x02; + break; + default: + logerror("Unsupported 'Write' command %X\n", m_eeprom_command); + break; + } + } + } + + if (data & 0x10) // Read + { + m_io_regs[0x04] = m_nvram[(m_eeprom_address << 1) + 1]; + m_io_regs[0x05] = m_nvram[m_eeprom_address << 1]; + data |= 0x01; + } + break; + + default: + ws_rom_device::write_io(space, offset, data); + break; + } + + m_io_regs[offset] = data; +} |