summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/vtech/memexp/sdloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/vtech/memexp/sdloader.cpp')
-rw-r--r--src/devices/bus/vtech/memexp/sdloader.cpp114
1 files changed, 108 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));
}