diff options
-rw-r--r-- | src/devices/bus/vtech/memexp/sdloader.cpp | 114 | ||||
-rw-r--r-- | src/devices/bus/vtech/memexp/sdloader.h | 14 |
2 files changed, 122 insertions, 6 deletions
diff --git a/src/devices/bus/vtech/memexp/sdloader.cpp b/src/devices/bus/vtech/memexp/sdloader.cpp index f20c19ebbc8..1799bac84ba 100644 --- a/src/devices/bus/vtech/memexp/sdloader.cpp +++ b/src/devices/bus/vtech/memexp/sdloader.cpp @@ -6,15 +6,26 @@ Notes: - Also works for VZ200 + - The loader can't format the SD card, so you need to do that yourself + Instructions for Linux: + * dd if=/dev/zero of=vz300.img count=2048 bs=1M + * mkfs.vfat vz300.img + * mount image and copy .vz files to it + * chdman createhd -o vz300.chd -i vz300.img -c none TODO: - - No SD card emulation, so only the memory expansion part works + - SPI clock needed too fast ***************************************************************************/ #include "emu.h" #include "sdloader.h" +#define LOG_GENERAL (1U << 0) +#define LOG_SPI (1U << 1) +#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + //************************************************************************** // DEVICE DEFINITIONS @@ -68,6 +79,18 @@ const tiny_rom_entry *vtech_sdloader_device::device_rom_region() const return ROM_NAME( sdloader ); } +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void vtech_sdloader_device::device_add_mconfig(machine_config &config) +{ + vtech_memexp_device::device_add_mconfig(config); + + SPI_SDCARD(config, m_sdcard, 0); + m_sdcard->spi_miso_callback().set(FUNC(vtech_sdloader_device::spi_miso_w)); +} + //************************************************************************** // LIVE DEVICE @@ -79,9 +102,12 @@ const tiny_rom_entry *vtech_sdloader_device::device_rom_region() const vtech_sdloader_device::vtech_sdloader_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : vtech_memexp_device(mconfig, VTECH_SDLOADER, tag, owner, clock), + m_sdcard(*this, "sdcard"), m_dosbank(*this, "dosbank"), m_dosview(*this, "dosview"), m_expbank(*this, "expbank"), + m_spi_clock_state(false), + m_spi_clock_cycles(0), m_vz300_mode(false) { } @@ -103,7 +129,16 @@ void vtech_sdloader_device::device_start() m_expbank->configure_entry(0, m_ram.get() + 0x10000); m_expbank->configure_entry(1, m_ram.get() + 0x18000); + // allocate timer for sdcard + m_spi_clock = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vtech_sdloader_device::spi_clock), this)); + // register for savestates + save_item(NAME(m_spi_clock_state)); + save_item(NAME(m_spi_clock_sysclk)); + save_item(NAME(m_spi_clock_cycles)); + save_item(NAME(m_in_bit)); + save_item(NAME(m_in_latch)); + save_item(NAME(m_out_latch)); save_item(NAME(m_vz300_mode)); save_pointer(NAME(m_ram), 0x20000); } @@ -119,6 +154,10 @@ void vtech_sdloader_device::device_reset() // rom enabled m_dosview.select(0); + + m_spi_clock->adjust(attotime::never); + m_spi_clock_cycles = 0; + m_spi_clock_state = false; } @@ -126,6 +165,48 @@ void vtech_sdloader_device::device_reset() // IMPLEMENTATION //************************************************************************** +TIMER_CALLBACK_MEMBER(vtech_sdloader_device::spi_clock) +{ + if (m_spi_clock_cycles > 0) + { + if (m_spi_clock_state) + { + m_in_latch <<= 1; + m_in_latch &= ~0x01; + m_in_latch |= m_in_bit; + + m_sdcard->spi_clock_w(1); + + m_spi_clock_cycles--; + } + else + { + if (m_spi_clock_cycles == 8) + LOGMASKED(LOG_SPI, "SPI transfer start\n"); + + m_sdcard->spi_mosi_w(BIT(m_out_latch, 7)); + m_sdcard->spi_clock_w(0); + + m_out_latch <<= 1; + } + + m_spi_clock_state = !m_spi_clock_state; + } + else + { + LOGMASKED(LOG_SPI, "SPI transfer done\n"); + m_spi_clock_state = false; + m_spi_clock->adjust(attotime::never); + } +} + +void vtech_sdloader_device::spi_miso_w(int state) +{ + LOGMASKED(LOG_SPI, "spi_miso_w: %d\n", state); + + m_in_bit = state; +} + void vtech_sdloader_device::mapper_w(uint8_t data) { // 7654---- not used @@ -141,23 +222,44 @@ void vtech_sdloader_device::mapper_w(uint8_t data) void vtech_sdloader_device::sdcfg_w(uint8_t data) { - logerror("sdcfg_w: %02x\n", data); + // 765432-- not used + // ------1- sd card cs + // -------0 clock speed + + LOGMASKED(LOG_SPI, "sdcfg_w: %02x\n", data); + + m_sdcard->spi_ss_w(BIT(data, 1)); + m_spi_clock_sysclk = bool(BIT(data, 0)); + + m_spi_clock_state = false; + m_spi_clock->adjust(attotime::never); } uint8_t vtech_sdloader_device::sdio_r() { - logerror("sdio_r\n"); - return 0xff; + LOGMASKED(LOG_SPI, "sdio_r: %02x\n", m_in_latch); + + return m_in_latch; } void vtech_sdloader_device::sdio_w(uint8_t data) { - logerror("sdio_w: %02x\n", data); + LOGMASKED(LOG_SPI, "sdio_w: %02x\n", data); + + m_out_latch = data; + m_spi_clock_cycles = 8; + + // TODO: too fast, also slightly different on vz200 + // code only waits for a single NOP before sending the next byte + if (m_spi_clock_sysclk) + m_spi_clock->adjust(attotime::from_hz(17.734470_MHz_XTAL / 1.5), 0, attotime::from_hz(17.734470_MHz_XTAL / 1.5)); + else + m_spi_clock->adjust(attotime::from_hz(100_kHz_XTAL), 0, attotime::from_hz(100_kHz_XTAL)); } void vtech_sdloader_device::mode_w(uint8_t data) { - logerror("Switching to %s mode\n", BIT(data, 0) ? "VZ-300" : "VZ-200"); + LOG("Switching to %s mode\n", BIT(data, 0) ? "VZ-300" : "VZ-200"); m_vz300_mode = bool(BIT(data, 0)); } diff --git a/src/devices/bus/vtech/memexp/sdloader.h b/src/devices/bus/vtech/memexp/sdloader.h index e2c80302ef6..fe1fa6ea313 100644 --- a/src/devices/bus/vtech/memexp/sdloader.h +++ b/src/devices/bus/vtech/memexp/sdloader.h @@ -11,6 +11,7 @@ #pragma once +#include "machine/spi_sdcard.h" #include "memexp.h" @@ -30,6 +31,7 @@ public: protected: virtual const tiny_rom_entry *device_rom_region() const override; + virtual void device_add_mconfig(machine_config &config) override; virtual void device_start() override; virtual void device_reset() override; @@ -37,10 +39,14 @@ protected: virtual void io_map(address_map &map) override; private: + required_device<spi_sdcard_device> m_sdcard; required_memory_bank m_dosbank; memory_view m_dosview; memory_bank_creator m_expbank; + TIMER_CALLBACK_MEMBER(spi_clock); + void spi_miso_w(int state); + void mapper_w(uint8_t data); void sdcfg_w(uint8_t data); uint8_t sdio_r(); @@ -50,6 +56,14 @@ private: uint8_t exp_ram_r(offs_t offset); void exp_ram_w(offs_t offset, uint8_t data); + emu_timer *m_spi_clock; + bool m_spi_clock_state; + bool m_spi_clock_sysclk; + int m_spi_clock_cycles; + int m_in_bit; + uint8_t m_in_latch; + uint8_t m_out_latch; + std::unique_ptr<uint8_t[]> m_ram; bool m_vz300_mode; }; |