vtech/sdloader: Add support for SPI SD card

This commit is contained in:
Dirk Best 2021-09-16 12:50:48 +02:00
parent 0fb4ca2c8b
commit 6b96a5d24b
2 changed files with 122 additions and 6 deletions

View file

@ -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));
}

View file

@ -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;
};