mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
apple2: support for the AppleIISD card [R. Belmont, Florian Reitz]
This commit is contained in:
parent
87ecae55e3
commit
ea8102906e
@ -2435,6 +2435,8 @@ if (BUSES["A2BUS"]~=null) then
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2sam.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2scsi.cpp",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2scsi.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2sd.cpp",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2sd.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2softcard.cpp",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2softcard.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/a2ssc.cpp",
|
||||
|
@ -4183,6 +4183,17 @@ if (MACHINES["SMARTMEDIA"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/spi_sdcard.h,MACHINES["SPISDCARD"] = true
|
||||
---------------------------------------------------
|
||||
if (MACHINES["SPISDCARD"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/spi_sdcard.cpp",
|
||||
MAME_DIR .. "src/devices/machine/spi_sdcard.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/appldriv.h,MACHINES["APPLE_DRIVE"] = true
|
||||
|
@ -651,6 +651,7 @@ MACHINES["SMC91C9X"] = true
|
||||
MACHINES["SEGA_SCU"] = true
|
||||
MACHINES["SMPC"] = true
|
||||
--MACHINES["SPG2XX"] = true
|
||||
--MACHINES["SPISDCARD"] = true
|
||||
MACHINES["STVCD"] = true
|
||||
--MACHINES["SUN4C_MMU"] = true
|
||||
MACHINES["SWTPC8212"] = true
|
||||
|
@ -692,6 +692,7 @@ MACHINES["SEGA_SCU"] = true
|
||||
MACHINES["SMPC"] = true
|
||||
MACHINES["SPG2XX"] = true
|
||||
MACHINES["SPG290"] = true
|
||||
MACHINES["SPISDCARD"] = true
|
||||
MACHINES["STVCD"] = true
|
||||
MACHINES["SUN4C_MMU"] = true
|
||||
MACHINES["SWTPC8212"] = true
|
||||
|
280
src/devices/bus/a2bus/a2sd.cpp
Normal file
280
src/devices/bus/a2bus/a2sd.cpp
Normal file
@ -0,0 +1,280 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*********************************************************************
|
||||
|
||||
a2sd.cpp
|
||||
|
||||
Implementation of the AppleIISD card by Florian Reitz
|
||||
https://github.com/freitz85/AppleIISd
|
||||
|
||||
AppleIISD has a Xilinx FPGA which implements a minimally hardware
|
||||
assisted SPI interface, and the SD card is thus driven in SPI
|
||||
mode rather than SD.
|
||||
|
||||
The SPI controller is fixed to SPI Mode 3 only.
|
||||
(shift on falling CLK edges, shift-then-latch).
|
||||
|
||||
Firmware is contained in an Atmel 28C64B parallel EEPROM, which
|
||||
has a Flash-style command set.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "a2sd.h"
|
||||
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_SPI (1U << 1)
|
||||
|
||||
//#define VERBOSE (LOG_COMMAND)
|
||||
#define LOG_OUTPUT_FUNC osd_printf_info
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
/***************************************************************************
|
||||
PARAMETERS
|
||||
***************************************************************************/
|
||||
|
||||
static constexpr u8 C0N1_ECE = 0x04; // external clock: toggles between 500 kHz internal clock and 1/2 of the 7M A2 bus clock
|
||||
static constexpr u8 C0N1_FRX = 0x10; // fast recieve: when enabled, both reads and writes of the SPI data register start a shift cycle
|
||||
[[unused]] static constexpr u8 C0N1_BSY = 0x20;
|
||||
static constexpr u8 C0N1_TC = 0x80; // SPI transfer complete
|
||||
|
||||
static constexpr u8 C0N3_CD = 0x40; // card detect
|
||||
static constexpr u8 C0N3_BIT_SS = 7;
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
DEFINE_DEVICE_TYPE(A2BUS_A2SD, a2bus_a2sd_device, "a2sd", "Apple II SD Card")
|
||||
|
||||
ROM_START( a2sd )
|
||||
ROM_REGION(0x2000, "flash", ROMREGION_ERASE00)
|
||||
ROM_LOAD( "appleiisd.bin", 0x000000, 0x000800, CRC(e82eea8a) SHA1(7e0acef01e622eeed6f8e87893d07c701bbef016) )
|
||||
ROM_END
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_add_mconfig - add device configuration
|
||||
//-------------------------------------------------
|
||||
void a2bus_a2sd_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
AT28C64B(config, m_flash, 0);
|
||||
|
||||
SPI_SDCARD(config, m_sdcard, 0);
|
||||
m_sdcard->spi_miso_callback().set(FUNC(a2bus_a2sd_device::spi_miso_w));
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// rom_region - device-specific ROM region
|
||||
//-------------------------------------------------
|
||||
|
||||
const tiny_rom_entry *a2bus_a2sd_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( a2sd );
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
a2bus_a2sd_device::a2bus_a2sd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, type, tag, owner, clock),
|
||||
device_a2bus_card_interface(mconfig, *this),
|
||||
m_flash(*this, "flash"),
|
||||
m_sdcard(*this, "sdcard"),
|
||||
m_datain(0), m_in_latch(0), m_out_latch(0), m_c0n1(0), m_c0n3(0x80), m_in_bit(0), m_shift_count(0)
|
||||
{
|
||||
}
|
||||
|
||||
a2bus_a2sd_device::a2bus_a2sd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
a2bus_a2sd_device(mconfig, A2BUS_A2SD, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void a2bus_a2sd_device::device_start()
|
||||
{
|
||||
m_shift_timer = timer_alloc(0);
|
||||
|
||||
save_item(NAME(m_datain));
|
||||
save_item(NAME(m_in_latch));
|
||||
save_item(NAME(m_out_latch));
|
||||
save_item(NAME(m_c0n1));
|
||||
save_item(NAME(m_c0n3));
|
||||
save_item(NAME(m_in_bit));
|
||||
save_item(NAME(m_shift_count));
|
||||
}
|
||||
|
||||
void a2bus_a2sd_device::device_reset()
|
||||
{
|
||||
m_shift_timer->adjust(attotime::never);
|
||||
m_shift_count = 0;
|
||||
m_sdcard->spi_clock_w(CLEAR_LINE);
|
||||
}
|
||||
|
||||
void a2bus_a2sd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
LOGMASKED(LOG_SPI, ">>>>>>> SHIFT %d (%c)\n", m_shift_count, (m_shift_count & 1) ? 'L' : 'S');
|
||||
if (!(m_shift_count & 1))
|
||||
{
|
||||
if (m_shift_count < 16)
|
||||
{
|
||||
m_out_latch <<= 1;
|
||||
}
|
||||
m_in_latch <<= 1;
|
||||
m_sdcard->spi_mosi_w(BIT(m_out_latch, 7));
|
||||
m_sdcard->spi_clock_w(CLEAR_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_in_latch &= ~0x01;
|
||||
m_in_latch |= m_in_bit;
|
||||
m_sdcard->spi_clock_w(ASSERT_LINE);
|
||||
|
||||
if (m_shift_count == 1)
|
||||
{
|
||||
m_datain = m_in_latch;
|
||||
LOGMASKED(LOG_SPI, "SPI: got %02x (in latch %02x)\n", m_datain, m_in_latch);
|
||||
}
|
||||
}
|
||||
|
||||
m_shift_count--;
|
||||
if (m_shift_count == 0)
|
||||
{
|
||||
m_shift_timer->adjust(attotime::never);
|
||||
m_c0n1 |= C0N1_TC; // set TC
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
read_c0nx - called for reads from this card's c0nx space
|
||||
-------------------------------------------------*/
|
||||
|
||||
u8 a2bus_a2sd_device::read_c0nx(u8 offset)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
m_c0n1 &= ~C0N1_TC; // clear TC
|
||||
// if FRX is set, both reads and writes trigger a shift cycle
|
||||
if (m_c0n1 & C0N1_FRX)
|
||||
{
|
||||
m_c0n1 &= ~C0N1_TC; // clear TC
|
||||
m_shift_count = 16;
|
||||
m_out_latch = 0xff;
|
||||
|
||||
if (m_c0n1 & C0N1_ECE)
|
||||
{
|
||||
m_shift_timer->adjust(attotime::from_hz(14.318181_MHz_XTAL / 4), 0, attotime::from_hz(14.318181_MHz_XTAL / 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_shift_timer->adjust(attotime::from_hz(500_kHz_XTAL), 0, attotime::from_hz(500_kHz_XTAL));
|
||||
}
|
||||
}
|
||||
return m_datain;
|
||||
|
||||
case 1:
|
||||
return m_c0n1;
|
||||
|
||||
case 2:
|
||||
return 0;
|
||||
|
||||
case 3:
|
||||
m_c0n3 &= ~C0N3_CD;
|
||||
m_c0n3 |= m_sdcard->get_card_present() ? 0 : C0N3_CD; // bit is set if no card is present
|
||||
return m_c0n3;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
write_c0nx - called for writes to this card's c0nx space
|
||||
-------------------------------------------------*/
|
||||
|
||||
void a2bus_a2sd_device::write_c0nx(u8 offset, u8 data)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
if (m_shift_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LOGMASKED(LOG_SPI, "SPI sending %02x\n", data);
|
||||
m_out_latch = data;
|
||||
m_sdcard->spi_mosi_w(BIT(m_out_latch, 7));
|
||||
m_c0n1 &= ~C0N1_TC; // clear TC
|
||||
m_shift_count = 16;
|
||||
// if ECE is set, clock is 3.58 MHz from the A2 bus, otherwise internally generated 500 kHz
|
||||
if (m_c0n1 & C0N1_ECE)
|
||||
{
|
||||
m_shift_timer->adjust(attotime::from_hz(14.318181_MHz_XTAL / 4), 0, attotime::from_hz(14.318181_MHz_XTAL/4));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_shift_timer->adjust(attotime::from_hz(500_kHz_XTAL), 0, attotime::from_hz(500_kHz_XTAL));
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_c0n1 &= 0xea;
|
||||
m_c0n1 |= (data & 0x15);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
break;
|
||||
|
||||
case 3:
|
||||
m_c0n3 &= 0x9f;
|
||||
m_c0n3 |= (data & 0x91);
|
||||
|
||||
m_sdcard->spi_ss_w(BIT(data, C0N3_BIT_SS));
|
||||
LOGMASKED(LOG_GENERAL, "/SS is %x\n", BIT(data, C0N3_BIT_SS));
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("a2sd: write %02x to c0n%x (%s)\n", data, offset, machine().describe_context().c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
read_cnxx - called for reads from this card's cnxx space
|
||||
-------------------------------------------------*/
|
||||
|
||||
u8 a2bus_a2sd_device::read_cnxx(u8 offset)
|
||||
{
|
||||
// slot image at 0
|
||||
return m_flash->read(offset);
|
||||
}
|
||||
|
||||
void a2bus_a2sd_device::write_cnxx(u8 offset, u8 data)
|
||||
{
|
||||
m_flash->write(offset, data);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
read_c800 - called for reads from this card's c800 space
|
||||
-------------------------------------------------*/
|
||||
|
||||
u8 a2bus_a2sd_device::read_c800(u16 offset)
|
||||
{
|
||||
return m_flash->read(offset + 0x100);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
write_c800 - called for writes to this card's c800 space
|
||||
-------------------------------------------------*/
|
||||
void a2bus_a2sd_device::write_c800(u16 offset, u8 data)
|
||||
{
|
||||
m_flash->write(offset + 0x100, data);
|
||||
}
|
67
src/devices/bus/a2bus/a2sd.h
Normal file
67
src/devices/bus/a2bus/a2sd.h
Normal file
@ -0,0 +1,67 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*********************************************************************
|
||||
|
||||
a2sd.h
|
||||
|
||||
Implementation of the AppleIISD card
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MAME_BUS_A2BUS_A2SD_H
|
||||
#define MAME_BUS_A2BUS_A2SD_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "a2bus.h"
|
||||
#include "machine/at28c64b.h"
|
||||
#include "machine/spi_sdcard.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
class a2bus_a2sd_device:
|
||||
public device_t,
|
||||
public device_a2bus_card_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a2bus_a2sd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
protected:
|
||||
a2bus_a2sd_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
// overrides of standard a2bus slot functions
|
||||
virtual u8 read_c0nx(u8 offset) override;
|
||||
virtual void write_c0nx(u8 offset, u8 data) override;
|
||||
virtual u8 read_cnxx(u8 offset) override;
|
||||
virtual void write_cnxx(u8 offset, u8 data) override;
|
||||
virtual u8 read_c800(uint16_t offset) override;
|
||||
virtual void write_c800(uint16_t offset, u8 data) override;
|
||||
|
||||
// SPI 4-wire interface
|
||||
WRITE_LINE_MEMBER(spi_miso_w) { m_in_bit = state; }
|
||||
|
||||
private:
|
||||
required_device<at28c64b_device> m_flash;
|
||||
required_device<spi_sdcard_device> m_sdcard;
|
||||
|
||||
u8 m_datain, m_in_latch, m_out_latch;
|
||||
u8 m_c0n1, m_c0n3;
|
||||
int m_in_bit;
|
||||
|
||||
int m_shift_count;
|
||||
emu_timer *m_shift_timer;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(A2BUS_A2SD, a2bus_a2sd_device)
|
||||
|
||||
#endif // MAME_BUS_A2BUS_A2SD_H
|
273
src/devices/machine/spi_sdcard.cpp
Normal file
273
src/devices/machine/spi_sdcard.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*
|
||||
SD Card emulation, SPI interface only currently
|
||||
Emulation by R. Belmont
|
||||
|
||||
This emulates an SDHC card, which means the block size is fixed at 512 bytes and makes things simpler.
|
||||
Adapting the code to also handle SD version 2 non-HC cards would be relatively straightforward as well;
|
||||
the block size defaults to 1 byte in that case but can be overridden with CMD16.
|
||||
|
||||
Adding the native 4-bit-wide SD interface is also possible
|
||||
|
||||
Multiple block read/write commands are not supported but would be straightforward to add.
|
||||
|
||||
Refrences:
|
||||
https://www.sdcard.org/downloads/pls/ (Physical Layer Simplified Specification)
|
||||
http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf
|
||||
https://embdev.net/attachment/39390/TOSHIBA_SD_Card_Specification.pdf
|
||||
http://elm-chan.org/docs/mmc/mmc_e.html
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "spi_sdcard.h"
|
||||
#include "imagedev/harddriv.h"
|
||||
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_COMMAND (1U << 1)
|
||||
#define LOG_SPI (1U << 2)
|
||||
|
||||
//#define VERBOSE (LOG_COMMAND)
|
||||
#define LOG_OUTPUT_FUNC osd_printf_info
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
static constexpr u8 DATA_RESPONSE_OK = 0x05;
|
||||
static constexpr u8 DATA_RESPONSE_IO_ERROR = 0x0d;
|
||||
|
||||
DEFINE_DEVICE_TYPE(SPI_SDCARD, spi_sdcard_device, "spi_sdcard", "SD Card (SPI Interface)")
|
||||
|
||||
spi_sdcard_device::spi_sdcard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, type, tag, owner, clock),
|
||||
write_miso(*this),
|
||||
m_image(*this, "image"),
|
||||
m_harddisk(nullptr),
|
||||
m_in_latch(0), m_out_latch(0), m_cmd_ptr(0), m_state(0), m_out_ptr(0), m_out_count(0), m_ss(0), m_in_bit(0),
|
||||
m_cur_bit(0), m_write_ptr(0), m_bACMD(false)
|
||||
{
|
||||
}
|
||||
|
||||
spi_sdcard_device::spi_sdcard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
spi_sdcard_device(mconfig, SPI_SDCARD, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void spi_sdcard_device::device_start()
|
||||
{
|
||||
write_miso.resolve_safe();
|
||||
save_item(NAME(m_in_latch));
|
||||
save_item(NAME(m_out_latch));
|
||||
save_item(NAME(m_cmd_ptr));
|
||||
save_item(NAME(m_state));
|
||||
save_item(NAME(m_out_ptr));
|
||||
save_item(NAME(m_out_count));
|
||||
save_item(NAME(m_ss));
|
||||
save_item(NAME(m_in_bit));
|
||||
save_item(NAME(m_cur_bit));
|
||||
save_item(NAME(m_write_ptr));
|
||||
save_item(NAME(m_cmd));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_bACMD));
|
||||
}
|
||||
|
||||
void spi_sdcard_device::device_reset()
|
||||
{
|
||||
m_harddisk = m_image->get_hard_disk_file();
|
||||
}
|
||||
|
||||
void spi_sdcard_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
HARDDISK(config, m_image).set_interface("spi_sdcard");
|
||||
}
|
||||
|
||||
void spi_sdcard_device::send_data(int count)
|
||||
{
|
||||
m_out_ptr = 0;
|
||||
m_out_count = count;
|
||||
}
|
||||
|
||||
void spi_sdcard_device::spi_clock_w(int state)
|
||||
{
|
||||
// only respond if selected
|
||||
if (m_ss)
|
||||
{
|
||||
// We implmement SPI Mode 3 signalling, in which we latch the data on
|
||||
// rising clock edges, and shift the data on falling clock edges.
|
||||
// See http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf for details
|
||||
// on the 4 SPI signalling modes. SD Cards can work in ether Mode 0 or Mode 3,
|
||||
// both of which shift on the falling edge and latch on the rising edge but
|
||||
// have opposite CLK polarity.
|
||||
|
||||
if (state)
|
||||
{
|
||||
m_in_latch &= ~0x01;
|
||||
m_in_latch |= m_in_bit;
|
||||
LOGMASKED(LOG_SPI, "\tsdcard: L %02x (%d) (out %02x)\n", m_in_latch, m_cur_bit, m_out_latch);
|
||||
m_cur_bit++;
|
||||
if (m_cur_bit == 8)
|
||||
{
|
||||
LOGMASKED(LOG_SPI, "SDCARD: got %02x\n", m_in_latch);
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case SD_STATE_IDLE:
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
m_cmd[i] = m_cmd[i + 1];
|
||||
}
|
||||
m_cmd[5] = m_in_latch;
|
||||
|
||||
if ((((m_cmd[0] & 0xc0) == 0x40) && (m_cmd[5] & 1)) && (m_out_count == 0))
|
||||
{
|
||||
do_command();
|
||||
}
|
||||
break;
|
||||
|
||||
case SD_STATE_WRITE_WAITFE:
|
||||
if (m_in_latch == 0xfe)
|
||||
{
|
||||
m_state = SD_STATE_WRITE_DATA;
|
||||
m_out_latch = 0xff;
|
||||
m_write_ptr = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SD_STATE_WRITE_DATA:
|
||||
m_data[m_write_ptr++] = m_in_latch;
|
||||
if (m_write_ptr == 514)
|
||||
{
|
||||
u32 blk = (m_cmd[1] << 24) | (m_cmd[2] << 16) | (m_cmd[3] << 8) | m_cmd[4];
|
||||
LOGMASKED(LOG_GENERAL, "writing LBA %x, data %02x %02x %02x %02x\n", blk, m_data[0], m_data[1], m_data[2], m_data[3]);
|
||||
if (hard_disk_write(m_harddisk, blk, &m_data[0]))
|
||||
{
|
||||
m_data[0] = DATA_RESPONSE_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data[0] = DATA_RESPONSE_IO_ERROR;
|
||||
}
|
||||
m_data[1] = 0x01;
|
||||
|
||||
m_state = SD_STATE_IDLE;
|
||||
send_data(2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_in_latch <<= 1;
|
||||
m_out_latch <<= 1;
|
||||
LOGMASKED(LOG_SPI, "\tsdcard: S %02x %02x (%d)\n", m_in_latch, m_out_latch, m_cur_bit);
|
||||
if (m_cur_bit == 8)
|
||||
{
|
||||
m_cur_bit = 0;
|
||||
}
|
||||
|
||||
if (m_cur_bit == 0)
|
||||
{
|
||||
if (m_out_count > 0)
|
||||
{
|
||||
m_out_latch = m_data[m_out_ptr++];
|
||||
LOGMASKED(LOG_SPI, "SDCARD: latching %02x (start of shift)\n", m_out_latch);
|
||||
m_out_count--;
|
||||
}
|
||||
}
|
||||
|
||||
write_miso(BIT(m_out_latch, 7) ? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spi_sdcard_device::do_command()
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "SDCARD: cmd %02d %02x %02x %02x %02x %02x\n", m_cmd[0] & 0x3f, m_cmd[1], m_cmd[2], m_cmd[3], m_cmd[4], m_cmd[5]);
|
||||
switch (m_cmd[0] & 0x3f)
|
||||
{
|
||||
case 0: // CMD0 - GO_IDLE_STATE
|
||||
if (m_harddisk)
|
||||
{
|
||||
m_data[0] = 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data[0] = 0x00;
|
||||
}
|
||||
send_data(1);
|
||||
break;
|
||||
|
||||
case 8: // CMD8 - SEND_IF_COND (SD v2 only)
|
||||
m_data[0] = 0x01;
|
||||
m_data[1] = 0;
|
||||
m_data[2] = 0;
|
||||
m_data[3] = 0;
|
||||
m_data[4] = 0xaa;
|
||||
send_data(5);
|
||||
break;
|
||||
|
||||
case 17: // CMD17 - READ_SINGLE_BLOCK
|
||||
if (m_harddisk)
|
||||
{
|
||||
m_data[0] = 0x00; // initial R1 response
|
||||
// data token occurs some time after the R1 response. A2SD expects at least 1
|
||||
// byte of space between R1 and the data packet.
|
||||
m_data[2] = 0xfe; // data token
|
||||
u32 blk = (m_cmd[1] << 24) | (m_cmd[2] << 16) | (m_cmd[3] << 8) | m_cmd[4];
|
||||
LOGMASKED(LOG_GENERAL, "reading LBA %x\n", blk);
|
||||
hard_disk_read(m_harddisk, blk, &m_data[3]);
|
||||
send_data(3 + 512 + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data[0] = 0xff; // show an error
|
||||
send_data(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 24: // CMD24 - WRITE_BLOCK
|
||||
m_data[0] = 0;
|
||||
send_data(1);
|
||||
m_state = SD_STATE_WRITE_WAITFE;
|
||||
break;
|
||||
|
||||
case 41:
|
||||
if (m_bACMD) // ACMD41 - SD_SEND_OP_COND
|
||||
{
|
||||
m_data[0] = 0;
|
||||
}
|
||||
else // CMD41 - illegal
|
||||
{
|
||||
m_data[0] = 0xff;
|
||||
}
|
||||
send_data(1);
|
||||
break;
|
||||
|
||||
case 55: // CMD55 - APP_CMD
|
||||
m_data[0] = 0x01;
|
||||
send_data(1);
|
||||
break;
|
||||
|
||||
case 58: // CMD58 - READ_OCR
|
||||
m_data[0] = 0;
|
||||
m_data[1] = 0x40; // indicate SDHC support
|
||||
m_data[2] = 0;
|
||||
m_data[3] = 0;
|
||||
m_data[4] = 0;
|
||||
send_data(5);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// if this is command 55, that's a prefix indicating the next command is an "app command" or "ACMD"
|
||||
if ((m_cmd[0] & 0x3f) == 55)
|
||||
{
|
||||
m_bACMD = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bACMD = false;
|
||||
}
|
||||
}
|
55
src/devices/machine/spi_sdcard.h
Normal file
55
src/devices/machine/spi_sdcard.h
Normal file
@ -0,0 +1,55 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
#ifndef MAME_MACHINE_SPI_SDCARD_H
|
||||
#define MAME_MACHINE_SPI_SDCARD_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imagedev/harddriv.h"
|
||||
|
||||
class spi_sdcard_device : public device_t
|
||||
{
|
||||
public:
|
||||
spi_sdcard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// SPI 4-wire interface
|
||||
auto spi_miso_callback() { return write_miso.bind(); }
|
||||
void spi_clock_w(int state);
|
||||
void spi_ss_w(int state) { m_ss = state; }
|
||||
void spi_mosi_w(int state) { m_in_bit = state; }
|
||||
|
||||
bool get_card_present() { return !(m_harddisk == nullptr); }
|
||||
|
||||
devcb_write_line write_miso;
|
||||
|
||||
protected:
|
||||
spi_sdcard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
required_device<harddisk_image_device> m_image;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
SD_STATE_IDLE = 0,
|
||||
SD_STATE_WRITE_WAITFE,
|
||||
SD_STATE_WRITE_DATA
|
||||
};
|
||||
|
||||
void send_data(int count);
|
||||
void do_command();
|
||||
|
||||
u8 m_data[520], m_cmd[6];
|
||||
hard_disk_file *m_harddisk;
|
||||
|
||||
u8 m_in_latch, m_out_latch;
|
||||
int m_cmd_ptr, m_state, m_out_ptr, m_out_count, m_ss, m_in_bit, m_cur_bit, m_write_ptr;
|
||||
bool m_bACMD;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SPI_SDCARD, spi_sdcard_device)
|
||||
|
||||
#endif // MAME_MACHINE_SPI_SDCARD_H
|
@ -159,6 +159,7 @@ MIG RAM page 2 $CE02 is the speaker/slot bitfield and $CE03 is the paddle/accele
|
||||
#include "bus/a2bus/a2pic.h"
|
||||
#include "bus/a2bus/a2sam.h"
|
||||
#include "bus/a2bus/a2scsi.h"
|
||||
#include "bus/a2bus/a2sd.h"
|
||||
#include "bus/a2bus/a2softcard.h"
|
||||
#include "bus/a2bus/a2ssc.h"
|
||||
#include "bus/a2bus/a2swyft.h"
|
||||
@ -4719,6 +4720,7 @@ static void apple2_cards(device_slot_interface &device)
|
||||
device.option_add("lancegs", A2BUS_LANCEGS); /* ///SHH SYSTEME LANceGS Card */
|
||||
device.option_add("q68", A2BUS_Q68); /* Stellation Q68 68000 card */
|
||||
device.option_add("q68plus", A2BUS_Q68PLUS); /* Stellation Q68 Plus 68000 card */
|
||||
device.option_add("a2sd", A2BUS_A2SD); /* Florian Reitz AppleIISD */
|
||||
}
|
||||
|
||||
static void apple2eaux_cards(device_slot_interface &device)
|
||||
|
Loading…
Reference in New Issue
Block a user