mirror of
https://github.com/holub/mame
synced 2025-04-16 21:44:32 +03:00
apple2: Add support for the BOOTI card [R. Belmont]
This commit is contained in:
parent
6704819c1f
commit
fa5977301e
@ -2416,6 +2416,8 @@ if (BUSES["A2BUS"]~=null) then
|
||||
MAME_DIR .. "src/devices/bus/a2bus/agat7ram.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/agat840k_hle.cpp",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/agat840k_hle.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/booti.cpp",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/booti.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/byte8251.cpp",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/byte8251.h",
|
||||
MAME_DIR .. "src/devices/bus/a2bus/ccs7710.cpp",
|
||||
|
@ -836,6 +836,18 @@ if (MACHINES["AT28C16"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/at28c64b.h,MACHINES["AT28C64B"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["AT28C64B"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/at28c64b.cpp",
|
||||
MAME_DIR .. "src/devices/machine/at28c64b.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/at29x.h,MACHINES["AT29X"] = true
|
||||
@ -981,6 +993,17 @@ if (MACHINES["CDP1879"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/ch376.h,MACHINES["CH376"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["CH376"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/ch376.cpp",
|
||||
MAME_DIR .. "src/devices/machine/ch376.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
|
@ -478,6 +478,7 @@ MACHINES["AMIGAFDC"] = true
|
||||
MACHINES["ARM_IOMD"] = true
|
||||
MACHINES["AT_KEYBC"] = true
|
||||
MACHINES["AT28C16"] = true
|
||||
MACHINES["AT28C64B"] = true
|
||||
MACHINES["AT29X"] = true
|
||||
MACHINES["AT45DBXX"] = true
|
||||
MACHINES["ATAFLASH"] = true
|
||||
@ -490,6 +491,7 @@ MACHINES["CDP1852"] = true
|
||||
MACHINES["CDP1871"] = true
|
||||
MACHINES["CDP1879"] = true
|
||||
--MACHINES["CDU76S"] = true
|
||||
MACHINES["CH376"] = true
|
||||
MACHINES["CHESSMACHINE"] = true
|
||||
MACHINES["CMOS40105"] = true
|
||||
MACHINES["COM52C50"] = true
|
||||
|
171
src/devices/bus/a2bus/booti.cpp
Normal file
171
src/devices/bus/a2bus/booti.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*********************************************************************
|
||||
|
||||
booti.cpp
|
||||
|
||||
Implementation of the BOOTI card
|
||||
|
||||
The BOOTI is an Apple II interface to the CH376 USB module.
|
||||
The CH376 is intended for use with small microcontrollers (or,
|
||||
you know, the 6502) to give them access to FAT-formatted
|
||||
flash drives. See ch376.cpp for details.
|
||||
|
||||
C0n0: read/write data to CH376
|
||||
C0n1: read status/write command to CH376
|
||||
C0n4: $C800 ROM bank (0-3)
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "booti.h"
|
||||
|
||||
/***************************************************************************
|
||||
PARAMETERS
|
||||
***************************************************************************/
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
DEFINE_DEVICE_TYPE(A2BUS_BOOTI, a2bus_booti_device, "a2booti", "Booti Card")
|
||||
|
||||
ROM_START( booti )
|
||||
ROM_REGION(0x2000, "flash", 0)
|
||||
ROM_LOAD( "bootifw09l.bin", 0x000000, 0x002000, CRC(be3f21ff) SHA1(f505ad4685cd44e4cce5b8d6d27b9c4fea159f11) )
|
||||
ROM_END
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_add_mconfig - add device configuration
|
||||
//-------------------------------------------------
|
||||
|
||||
void a2bus_booti_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
AT28C64B(config, "flash", 0);
|
||||
|
||||
CH376(config, "ch376");
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// rom_region - device-specific ROM region
|
||||
//-------------------------------------------------
|
||||
|
||||
const tiny_rom_entry *a2bus_booti_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( booti );
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
a2bus_booti_device::a2bus_booti_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_ch376(*this, "ch376"),
|
||||
m_rombank(0)
|
||||
{
|
||||
}
|
||||
|
||||
a2bus_booti_device::a2bus_booti_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
a2bus_booti_device(mconfig, A2BUS_BOOTI, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void a2bus_booti_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_rombank));
|
||||
}
|
||||
|
||||
void a2bus_booti_device::device_reset()
|
||||
{
|
||||
m_rombank = 0;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
read_c0nx - called for reads from this card's c0nx space
|
||||
-------------------------------------------------*/
|
||||
|
||||
uint8_t a2bus_booti_device::read_c0nx(uint8_t offset)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return m_ch376->read(offset);
|
||||
|
||||
case 4:
|
||||
return m_rombank / 0x800;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
write_c0nx - called for writes to this card's c0nx space
|
||||
-------------------------------------------------*/
|
||||
|
||||
void a2bus_booti_device::write_c0nx(uint8_t offset, uint8_t data)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
m_ch376->write(offset, data);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
m_rombank = 0x800 * (data & 3);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("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
|
||||
-------------------------------------------------*/
|
||||
|
||||
uint8_t a2bus_booti_device::read_cnxx(uint8_t offset)
|
||||
{
|
||||
// slot image at 0
|
||||
return m_flash->read(offset);
|
||||
}
|
||||
|
||||
void a2bus_booti_device::write_cnxx(uint8_t offset, uint8_t data)
|
||||
{
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
read_c800 - called for reads from this card's c800 space
|
||||
-------------------------------------------------*/
|
||||
|
||||
uint8_t a2bus_booti_device::read_c800(uint16_t offset)
|
||||
{
|
||||
return m_flash->read(offset + m_rombank);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
write_c800 - called for writes to this card's c800 space
|
||||
-------------------------------------------------*/
|
||||
void a2bus_booti_device::write_c800(uint16_t offset, uint8_t data)
|
||||
{
|
||||
// the card appears not to pass writes to $CFFF to the EEPROM,
|
||||
// otherwise there's a false read of the next opcode after a $CFFF write and we crash.
|
||||
if (offset < 0x7ff)
|
||||
{
|
||||
m_flash->write(offset + m_rombank, data);
|
||||
}
|
||||
}
|
58
src/devices/bus/a2bus/booti.h
Normal file
58
src/devices/bus/a2bus/booti.h
Normal file
@ -0,0 +1,58 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*********************************************************************
|
||||
|
||||
booti.h
|
||||
|
||||
Implementation of the Booti card
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MAME_BUS_A2BUS_BOOTI_H
|
||||
#define MAME_BUS_A2BUS_BOOTI_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "a2bus.h"
|
||||
#include "machine/at28c64b.h"
|
||||
#include "machine/ch376.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
class a2bus_booti_device:
|
||||
public device_t,
|
||||
public device_a2bus_card_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a2bus_booti_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
protected:
|
||||
a2bus_booti_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;
|
||||
|
||||
// overrides of standard a2bus slot functions
|
||||
virtual uint8_t read_c0nx(uint8_t offset) override;
|
||||
virtual void write_c0nx(uint8_t offset, uint8_t data) override;
|
||||
virtual uint8_t read_cnxx(uint8_t offset) override;
|
||||
virtual void write_cnxx(uint8_t offset, uint8_t data) override;
|
||||
virtual uint8_t read_c800(uint16_t offset) override;
|
||||
virtual void write_c800(uint16_t offset, uint8_t data) override;
|
||||
|
||||
private:
|
||||
required_device<at28c64b_device> m_flash;
|
||||
required_device<ch376_device> m_ch376;
|
||||
|
||||
int m_rombank;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(A2BUS_BOOTI, a2bus_booti_device)
|
||||
|
||||
#endif // MAME_BUS_A2BUS_BOOTI_H
|
279
src/devices/machine/at28c64b.cpp
Normal file
279
src/devices/machine/at28c64b.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:smf, R. Belmont
|
||||
/***************************************************************************
|
||||
ATMEL AT28C64B
|
||||
|
||||
64K ( 8K x 8 ) Parallel EEPROM with flash-like in-band signalling
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "machine/at28c64b.h"
|
||||
|
||||
static constexpr int AT28C64B_DATA_BYTES = 0x10000;
|
||||
static constexpr int AT28C64B_ID_BYTES = 0x40;
|
||||
static constexpr int AT28C64B_TOTAL_BYTES = AT28C64B_DATA_BYTES + AT28C64B_ID_BYTES;
|
||||
|
||||
static constexpr int AT28C64B_ID_OFFSET = 0x1fc0;
|
||||
static constexpr int AT28C64B_SECTOR_SIZE = 0x40;
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
void at28c64b_device::at28c64b_map8(address_map &map)
|
||||
{
|
||||
map(0x00000, 0x1003f).ram();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(AT28C64B, at28c64b_device, "at28c64b", "AT28C64B 8Kx8 EEPROM")
|
||||
|
||||
//-------------------------------------------------
|
||||
// at28c64b_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
at28c64b_device::at28c64b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, AT28C64B, tag, owner, clock),
|
||||
device_memory_interface(mconfig, *this),
|
||||
device_nvram_interface(mconfig, *this),
|
||||
m_space_config("at28c64b", ENDIANNESS_BIG, 8, 17, 0, address_map_constructor(FUNC(at28c64b_device::at28c64b_map8), this)),
|
||||
m_a9_12v(0),
|
||||
m_oe_12v(0),
|
||||
m_last_write(-1),
|
||||
m_state(0),
|
||||
m_bytes_in_sector(0),
|
||||
m_default_data(*this, DEVICE_SELF)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// memory_space_config - return a description of
|
||||
// any address spaces owned by this device
|
||||
//-------------------------------------------------
|
||||
|
||||
device_memory_interface::space_config_vector at28c64b_device::memory_space_config() const
|
||||
{
|
||||
return space_config_vector {
|
||||
std::make_pair(0, &m_space_config)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void at28c64b_device::device_start()
|
||||
{
|
||||
m_write_timer = timer_alloc(0);
|
||||
|
||||
save_item( NAME(m_a9_12v) );
|
||||
save_item( NAME(m_oe_12v) );
|
||||
save_item( NAME(m_last_write) );
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// nvram_default - called to initialize NVRAM to
|
||||
// its default state
|
||||
//-------------------------------------------------
|
||||
|
||||
void at28c64b_device::nvram_default()
|
||||
{
|
||||
uint16_t default_value = 0xff;
|
||||
for( offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++ )
|
||||
{
|
||||
space(AS_PROGRAM).write_byte( offs, default_value );
|
||||
}
|
||||
|
||||
/* populate from a memory region if present */
|
||||
printf("checking for default\n");
|
||||
if (m_default_data.found())
|
||||
{
|
||||
printf("Got default data\n");
|
||||
for( offs_t offs = 0; offs < AT28C64B_DATA_BYTES; offs++ )
|
||||
space(AS_PROGRAM).write_byte(offs, m_default_data[offs]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// nvram_read - called to read NVRAM from the
|
||||
// .nv file
|
||||
//-------------------------------------------------
|
||||
|
||||
void at28c64b_device::nvram_read( emu_file &file )
|
||||
{
|
||||
std::vector<uint8_t> buffer( AT28C64B_TOTAL_BYTES );
|
||||
|
||||
file.read( &buffer[0], AT28C64B_TOTAL_BYTES );
|
||||
|
||||
for( offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++ )
|
||||
{
|
||||
space(AS_PROGRAM).write_byte( offs, buffer[ offs ] );
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// nvram_write - called to write NVRAM to the
|
||||
// .nv file
|
||||
//-------------------------------------------------
|
||||
|
||||
void at28c64b_device::nvram_write( emu_file &file )
|
||||
{
|
||||
std::vector<uint8_t> buffer ( AT28C64B_TOTAL_BYTES );
|
||||
|
||||
for( offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++ )
|
||||
{
|
||||
buffer[ offs ] = space(AS_PROGRAM).read_byte( offs );
|
||||
}
|
||||
|
||||
file.write( &buffer[0], AT28C64B_TOTAL_BYTES );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// READ/WRITE HANDLERS
|
||||
//**************************************************************************
|
||||
|
||||
void at28c64b_device::write(offs_t offset, uint8_t data)
|
||||
{
|
||||
logerror("%s: AT28C64B: write( %04x, %02x ) state %d last_write %d\n", machine().describe_context(), offset, data, m_state, m_last_write);
|
||||
|
||||
if (m_state == STATE_SECTOR_WRITE)
|
||||
{
|
||||
logerror("SECTOR WRITE: %02x @ %x\n", data, offset);
|
||||
this->space(AS_PROGRAM).write_byte(offset, data);
|
||||
m_last_write = data;
|
||||
m_write_timer->adjust(attotime::from_usec(10));
|
||||
m_bytes_in_sector--;
|
||||
if (m_bytes_in_sector == 0)
|
||||
{
|
||||
m_state = STATE_WRITE_PROTECT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_last_write >= 0 )
|
||||
{
|
||||
// logerror( "%s: AT28C64B: write( %04x, %02x ) busy\n", machine().describe_context(), offset, data );
|
||||
}
|
||||
else if( m_oe_12v )
|
||||
{
|
||||
// logerror( "%s: AT28C64B: write( %04x, %02x ) erase\n", machine().describe_context(), offset, data );
|
||||
if( m_last_write < 0 )
|
||||
{
|
||||
for( offs_t offs = 0; offs < AT28C64B_TOTAL_BYTES; offs++ )
|
||||
{
|
||||
this->space(AS_PROGRAM).write_byte( offs, 0xff );
|
||||
}
|
||||
|
||||
m_last_write = 0xff;
|
||||
m_write_timer->adjust( attotime::from_usec( 10 ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((offset == 0x1555) && (data == 0xaa))
|
||||
{
|
||||
m_state = STATE_ID_1;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_state == STATE_ID_1) && (offset == 0xaaa) && (data == 0x55))
|
||||
{
|
||||
m_state = STATE_ID_2;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_state == STATE_ID_2) && (offset == 0x1555) && (data == 0xa0))
|
||||
{
|
||||
m_state = STATE_SECTOR_WRITE;
|
||||
m_bytes_in_sector = AT28C64B_SECTOR_SIZE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state == STATE_WRITE_PROTECT)
|
||||
{
|
||||
logerror("%s: write %02x to %x while write protected\n", machine().describe_context(), data, offset);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_a9_12v) && (offset >= AT28C64B_ID_OFFSET) && (offset < (AT28C64B_ID_OFFSET + AT28C64B_ID_BYTES)))
|
||||
{
|
||||
offset += AT28C64B_ID_BYTES;
|
||||
}
|
||||
|
||||
if( m_last_write < 0 && this->space(AS_PROGRAM).read_byte( offset ) != data )
|
||||
{
|
||||
this->space(AS_PROGRAM).write_byte( offset, data );
|
||||
m_last_write = data;
|
||||
m_write_timer->adjust( attotime::from_usec( 10 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t at28c64b_device::read(offs_t offset)
|
||||
{
|
||||
if( m_last_write >= 0 )
|
||||
{
|
||||
uint8_t data = m_last_write ^ 0x80;
|
||||
// logerror( "%s: AT28C64B: read( %04x ) write status %02x\n", machine().describe_context(), offset, data );
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( m_a9_12v && offset >= AT28C64B_ID_OFFSET )
|
||||
{
|
||||
offset += AT28C64B_ID_BYTES;
|
||||
}
|
||||
|
||||
uint8_t data = this->space(AS_PROGRAM).read_byte( offset );
|
||||
// logerror( "%s: AT28C64B: read( %04x ) data %02x\n", machine().describe_context(), offset, data );
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER( at28c64b_device::set_a9_12v )
|
||||
{
|
||||
state &= 1;
|
||||
if( m_a9_12v != state )
|
||||
{
|
||||
// logerror( "%s: AT28C64B: set_a9_12v( %d )\n", machine().describe_context(), state );
|
||||
m_a9_12v = state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER( at28c64b_device::set_oe_12v )
|
||||
{
|
||||
state &= 1;
|
||||
if( m_oe_12v != state )
|
||||
{
|
||||
// logerror( "%s: AT28C64B: set_oe_12v( %d )\n", machine().describe_context(), state );
|
||||
m_oe_12v = state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void at28c64b_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
switch( id )
|
||||
{
|
||||
case 0:
|
||||
m_last_write = -1;
|
||||
break;
|
||||
}
|
||||
}
|
80
src/devices/machine/at28c64b.h
Normal file
80
src/devices/machine/at28c64b.h
Normal file
@ -0,0 +1,80 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:smf
|
||||
/***************************************************************************
|
||||
|
||||
ATMEL AT28C64B
|
||||
|
||||
64K ( 8K x 8 ) Parallel EEPROM
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_AT28C64B_H
|
||||
#define MAME_MACHINE_AT28C64B_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> at28c64b_device
|
||||
|
||||
class at28c64b_device :
|
||||
public device_t,
|
||||
public device_memory_interface,
|
||||
public device_nvram_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
at28c64b_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
void write(offs_t offset, u8 data);
|
||||
u8 read(offs_t offset);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
// device_memory_interface overrides
|
||||
virtual space_config_vector memory_space_config() const override;
|
||||
|
||||
// device_nvram_interface overrides
|
||||
virtual void nvram_default() override;
|
||||
virtual void nvram_read(emu_file &file) override;
|
||||
virtual void nvram_write(emu_file &file) override;
|
||||
|
||||
private:
|
||||
// internal state
|
||||
enum
|
||||
{
|
||||
STATE_IDLE,
|
||||
STATE_ID_1,
|
||||
STATE_ID_2,
|
||||
STATE_SECTOR_WRITE,
|
||||
STATE_WRITE_PROTECT
|
||||
};
|
||||
|
||||
address_space_config m_space_config;
|
||||
emu_timer *m_write_timer;
|
||||
int m_a9_12v;
|
||||
int m_oe_12v;
|
||||
int m_last_write;
|
||||
int m_state;
|
||||
int m_bytes_in_sector;
|
||||
|
||||
optional_region_ptr<uint8_t> m_default_data;
|
||||
|
||||
// I/O operations
|
||||
DECLARE_WRITE_LINE_MEMBER( set_a9_12v );
|
||||
DECLARE_WRITE_LINE_MEMBER( set_oe_12v );
|
||||
|
||||
void at28c64b_map8(address_map &map);
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(AT28C64B, at28c64b_device)
|
||||
|
||||
#endif // MAME_MACHINE_AT28C64B_H
|
505
src/devices/machine/ch376.cpp
Normal file
505
src/devices/machine/ch376.cpp
Normal file
@ -0,0 +1,505 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/***************************************************************************
|
||||
|
||||
ch376.h
|
||||
|
||||
"File manage and control chip CH376"
|
||||
https://www.mpja.com/download/ch376ds1.pdf
|
||||
|
||||
This is a module intended to offload USB and USB mass storage
|
||||
I/O from a small microcontroller or microprocessor.
|
||||
|
||||
It has 3 host interfaces:
|
||||
1) A regular 8-bit bus with 8 data lines, an address line,
|
||||
chip select, read enable, and write enable lines
|
||||
2) An SPI bus interface (SCS, SCK, MOSI, MISO lines)
|
||||
3) An asynchronous serial interface (TxD and RxD lines)
|
||||
|
||||
And 2 guest interfaces: USB 2.0 and a second 4-wire SPI bus for SD/MMC/TF cards.
|
||||
|
||||
The module can give high level directory/open/close/read/write access to
|
||||
files on a FAT12, FAT16, or FAT32 filesystem.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "emuopts.h"
|
||||
#include "machine/ch376.h"
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(CH376, ch376_device, "ch376", "CH376 USB/file manager module")
|
||||
|
||||
static constexpr u8 STATUS_USB_INT_SUCCESS = 0x14;
|
||||
static constexpr u8 STATUS_USB_INT_CONNECT = 0x15;
|
||||
static constexpr u8 STATUS_USB_INT_DISK_READ = 0x1d;
|
||||
static constexpr u8 STATUS_USB_INT_DISK_WRITE = 0x1e;
|
||||
static constexpr u8 STATUS_USB_INT_DISK_ERR = 0x1f;
|
||||
static constexpr u8 STATUS_ERR_MISS_FILE = 0x42;
|
||||
|
||||
static constexpr u8 CMD_GET_IC_VER = 0x01;
|
||||
static constexpr u8 CMD_GET_FILE_SIZE = 0x0c;
|
||||
static constexpr u8 CMD_SET_USB_MODE = 0x15;
|
||||
static constexpr u8 CMD_GET_STATUS = 0x22;
|
||||
static constexpr u8 CMD_RD_USB_DATA0 = 0x27;
|
||||
static constexpr u8 CMD_WR_REQ_DATA = 0x2d;
|
||||
static constexpr u8 CMD_SET_FILE_NAME = 0x2f;
|
||||
static constexpr u8 CMD_DISK_MOUNT = 0x31;
|
||||
static constexpr u8 CMD_FILE_OPEN = 0x32;
|
||||
static constexpr u8 CMD_FILE_ENUM_GO = 0x33;
|
||||
static constexpr u8 CMD_FILE_CLOSE = 0x36;
|
||||
static constexpr u8 CMD_BYTE_LOCATE = 0x39;
|
||||
static constexpr u8 CMD_BYTE_READ = 0x3a;
|
||||
static constexpr u8 CMD_BYTE_READ_GO = 0x3b;
|
||||
static constexpr u8 CMD_BYTE_WRITE = 0x3c;
|
||||
static constexpr u8 CMD_BYTE_WR_GO = 0x3d;
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// ch376_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
ch376_device::ch376_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, CH376, tag, owner, clock),
|
||||
m_state(0),
|
||||
m_status(0),
|
||||
m_int_status(0),
|
||||
m_data(0),
|
||||
m_last_command(0),
|
||||
m_pointer(0),
|
||||
m_file_pos(0),
|
||||
m_dataPtr(0),
|
||||
m_dataLen(0),
|
||||
m_readLen(0),
|
||||
m_cur_file_size(0)
|
||||
{
|
||||
std::fill_n(&m_file_name[0], sizeof(m_file_name), 0);
|
||||
std::fill_n(&m_dataBuffer[0], sizeof(m_dataBuffer), 0);
|
||||
m_current_directory.clear();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void ch376_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_state));
|
||||
save_item(NAME(m_status));
|
||||
save_item(NAME(m_int_status));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_file_name));
|
||||
save_item(NAME(m_pointer));
|
||||
save_item(NAME(m_dataPtr));
|
||||
save_item(NAME(m_dataLen));
|
||||
save_item(NAME(m_readLen));
|
||||
|
||||
m_directory.reset();
|
||||
m_file.reset();
|
||||
}
|
||||
|
||||
u8 ch376_device::read(offs_t offset)
|
||||
{
|
||||
if (offset & 1)
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_GET_STATUS:
|
||||
m_state = STATE_IDLE;
|
||||
return m_int_status;
|
||||
|
||||
case STATE_WRITE_SIZE_REPLY:
|
||||
m_state = STATE_READ_WRITE_DATA;
|
||||
m_dataPtr = 0;
|
||||
return m_data;
|
||||
}
|
||||
|
||||
if ((m_dataLen > 0) && (m_dataPtr < m_dataLen))
|
||||
{
|
||||
return m_dataBuffer[m_dataPtr++];
|
||||
}
|
||||
|
||||
return m_data;
|
||||
}
|
||||
|
||||
void ch376_device::write(offs_t offset, u8 data)
|
||||
{
|
||||
if (offset & 1) // write command
|
||||
{
|
||||
//printf("CH376: write command %02x\n", data);
|
||||
m_last_command = data;
|
||||
switch (data)
|
||||
{
|
||||
case CMD_GET_IC_VER:
|
||||
m_dataBuffer[0] = 0x41; //
|
||||
m_dataPtr = 0;
|
||||
m_dataLen = 1;
|
||||
break;
|
||||
|
||||
case CMD_GET_FILE_SIZE:
|
||||
m_state = STATE_GET_FILE_SIZE;
|
||||
break;
|
||||
|
||||
case CMD_SET_USB_MODE:
|
||||
m_state = STATE_USB_MODE_SET;
|
||||
break;
|
||||
|
||||
case CMD_GET_STATUS:
|
||||
m_state = STATE_GET_STATUS;
|
||||
break;
|
||||
|
||||
case CMD_RD_USB_DATA0:
|
||||
m_int_status = STATUS_USB_INT_DISK_READ;
|
||||
break;
|
||||
|
||||
case CMD_WR_REQ_DATA:
|
||||
{
|
||||
int lenToWrite = (m_readLen >= 255) ? 255 : m_readLen;
|
||||
m_data = (lenToWrite & 0xff);
|
||||
m_readLen -= lenToWrite;
|
||||
m_state = STATE_WRITE_SIZE_REPLY;
|
||||
m_dataLen = lenToWrite;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_SET_FILE_NAME:
|
||||
m_state = STATE_SET_FILE_NAME;
|
||||
m_pointer = 0;
|
||||
break;
|
||||
|
||||
case CMD_DISK_MOUNT:
|
||||
m_int_status = STATUS_USB_INT_CONNECT;
|
||||
break;
|
||||
|
||||
case CMD_FILE_OPEN:
|
||||
/*
|
||||
CH376 allows paths with a leading / or \ to indicate the root of the SD card.
|
||||
Directories are chained by an unusual method: start with the root dir (leading path separator),
|
||||
then open each subdirectory without a leading path separator, and finally open the file without
|
||||
a leading path separator.
|
||||
|
||||
The BOOTI card ignores directories entirely, so the implmentation here is not tested with that
|
||||
scenario but it should work.
|
||||
*/
|
||||
if (m_file_name[strlen(m_file_name) - 1] == '*')
|
||||
{
|
||||
// it's a directory
|
||||
// remove the wildcard
|
||||
m_file_name[strlen(m_file_name) - 1] = '\0';
|
||||
std::string tmpPath(machine().options().share_directory());
|
||||
tmpPath.append(PATH_SEPARATOR);
|
||||
if ((m_file_name[0] == '/') || (m_file_name[0] == '\\'))
|
||||
{
|
||||
tmpPath.append(&m_file_name[1]);
|
||||
m_current_directory.clear();
|
||||
m_current_directory = tmpPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpPath.append(m_file_name);
|
||||
m_current_directory.append(PATH_SEPARATOR);
|
||||
m_current_directory.append(tmpPath);
|
||||
}
|
||||
m_directory = osd::directory::open(tmpPath);
|
||||
if (generateNextDirEntry())
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_DISK_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_DISK_ERR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string tmpPath = m_current_directory;
|
||||
u64 size;
|
||||
|
||||
// compose this name with the last directory opened, unless it starts with a path separator
|
||||
tmpPath.append(PATH_SEPARATOR);
|
||||
if ((m_file_name[0] == '/') || (m_file_name[0] == '\\'))
|
||||
{
|
||||
tmpPath.append(&m_file_name[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpPath.append(m_file_name);
|
||||
}
|
||||
|
||||
if (osd_file::open(tmpPath, OPEN_FLAG_READ|OPEN_FLAG_WRITE, m_file, size) == osd_file::error::NONE)
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_SUCCESS;
|
||||
m_cur_file_size = size & 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_DISK_ERR;
|
||||
m_cur_file_size = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_FILE_ENUM_GO:
|
||||
if (generateNextDirEntry())
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_DISK_READ;
|
||||
}
|
||||
else // end of directory
|
||||
{
|
||||
m_int_status = STATUS_ERR_MISS_FILE;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_FILE_CLOSE:
|
||||
m_directory.reset();
|
||||
m_file.reset();
|
||||
m_int_status = STATUS_USB_INT_DISK_READ;
|
||||
break;
|
||||
|
||||
case CMD_BYTE_LOCATE:
|
||||
m_state = STATE_SEEK;
|
||||
break;
|
||||
|
||||
case CMD_BYTE_READ:
|
||||
m_state = STATE_READ_SIZE;
|
||||
break;
|
||||
|
||||
case CMD_BYTE_READ_GO:
|
||||
if (m_readLen > 0)
|
||||
{
|
||||
doNextFileRead();
|
||||
m_int_status = STATUS_USB_INT_DISK_READ;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dataBuffer[0] = 0;
|
||||
m_dataLen = 0;
|
||||
m_int_status = STATUS_USB_INT_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_BYTE_WRITE:
|
||||
m_state = STATE_READ_SIZE;
|
||||
break;
|
||||
|
||||
case CMD_BYTE_WR_GO:
|
||||
if (m_dataPtr > 0)
|
||||
{
|
||||
u32 actual;
|
||||
m_state = STATE_IDLE;
|
||||
m_file->write(&m_dataBuffer[0], m_file_pos, m_dataLen, actual);
|
||||
m_file_pos += m_dataLen;
|
||||
if (m_readLen > 0)
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_DISK_WRITE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_int_status = STATUS_USB_INT_SUCCESS;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("CH376: unhandled command %02x\n", data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_state)
|
||||
{
|
||||
case STATE_USB_MODE_SET:
|
||||
m_state = STATE_IDLE;
|
||||
break;
|
||||
|
||||
case STATE_SET_FILE_NAME:
|
||||
m_file_name[m_pointer++] = data;
|
||||
if (m_pointer == 14)
|
||||
{
|
||||
m_state = STATE_IDLE;
|
||||
// is this shorter than 8.3?
|
||||
if (m_file_name[8] == '\0')
|
||||
{
|
||||
int idx = 8;
|
||||
while (m_file_name[idx] == '\0')
|
||||
{
|
||||
idx--;
|
||||
}
|
||||
idx++;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
m_file_name[idx + i] = m_file_name[9 + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SEEK:
|
||||
case STATE_SEEK1:
|
||||
case STATE_SEEK2:
|
||||
m_file_pos >>= 8;
|
||||
m_file_pos |= (data << 24);
|
||||
m_state++;
|
||||
break;
|
||||
|
||||
case STATE_SEEK3:
|
||||
m_file_pos >>= 8;
|
||||
m_file_pos |= (data << 24);
|
||||
m_state = STATE_IDLE;
|
||||
m_int_status = STATUS_USB_INT_SUCCESS;
|
||||
break;
|
||||
|
||||
case STATE_READ_SIZE:
|
||||
m_readLen = data;
|
||||
m_state++;
|
||||
break;
|
||||
|
||||
case STATE_READ_SIZE2:
|
||||
m_readLen |= (data << 8);
|
||||
m_state = STATE_IDLE;
|
||||
m_int_status = STATUS_USB_INT_DISK_READ;
|
||||
|
||||
if (m_last_command == 0x3a)
|
||||
{
|
||||
doNextFileRead();
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_READ_WRITE_DATA:
|
||||
m_dataBuffer[m_dataPtr++] = data;
|
||||
break;
|
||||
|
||||
case STATE_GET_FILE_SIZE:
|
||||
// the host must write 0x68 here; it's unclear what the real chip does if the value doesn't match.
|
||||
// reply with the size of the currently open file.
|
||||
m_dataBuffer[0] = m_cur_file_size & 0xff;
|
||||
m_dataBuffer[1] = (m_cur_file_size >> 8) & 0xff;
|
||||
m_dataBuffer[2] = (m_cur_file_size >> 16) & 0xff;
|
||||
m_dataBuffer[3] = (m_cur_file_size >> 24) & 0xff;
|
||||
m_dataPtr = 0;
|
||||
m_dataLen = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ch376_device::generateNextDirEntry()
|
||||
{
|
||||
const osd::directory::entry *ourEntry;
|
||||
|
||||
m_dataPtr = 0;
|
||||
m_dataLen = 0;
|
||||
|
||||
// no directory?
|
||||
if (m_directory == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// is there an entry?
|
||||
if ((ourEntry = m_directory->read()) == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::fill_n(&m_dataBuffer[0], sizeof(m_dataBuffer), 0);
|
||||
m_dataBuffer[0] = 32;
|
||||
if (ourEntry->type == osd::directory::entry::entry_type::DIR)
|
||||
{
|
||||
strncpy(reinterpret_cast<char *>(&m_dataBuffer[1]), ourEntry->name, 8);
|
||||
m_dataBuffer[0xc] == 0x10; // directory type
|
||||
}
|
||||
else if (ourEntry->type == osd::directory::entry::entry_type::FILE)
|
||||
{
|
||||
int dotIdx = 8;
|
||||
for (int idx = (strlen(ourEntry->name) - 1); idx >= 0; idx--)
|
||||
{
|
||||
if (ourEntry->name[idx] == '.')
|
||||
{
|
||||
dotIdx = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int baseLen = std::min(8, dotIdx);
|
||||
for (int idx = 0; idx < baseLen; idx++)
|
||||
{
|
||||
m_dataBuffer[idx + 1] = toupper(ourEntry->name[idx]);
|
||||
if (ourEntry->name[idx] == '\0')
|
||||
{
|
||||
baseLen = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// copy the extension (up to 3 chars, if we found one)
|
||||
if (ourEntry->name[dotIdx] == '.')
|
||||
{
|
||||
dotIdx++;
|
||||
for (int idx = 0; idx < 3; idx++)
|
||||
{
|
||||
if ((idx + dotIdx) > strlen(ourEntry->name))
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_dataBuffer[idx + 8 + 1] = toupper(ourEntry->name[idx + dotIdx]);
|
||||
}
|
||||
}
|
||||
|
||||
m_dataBuffer[0xc] = 0; // no attributes
|
||||
|
||||
if (ourEntry->size >= u64(0x100000000))
|
||||
{
|
||||
m_dataBuffer[0x1d] = 0xff;
|
||||
m_dataBuffer[0x1e] = 0xff;
|
||||
m_dataBuffer[0x1f] = 0xff;
|
||||
m_dataBuffer[0x20] = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dataBuffer[0x1d] = (ourEntry->size & 0xff);
|
||||
m_dataBuffer[0x1e] = ((ourEntry->size >> 8) & 0xff);
|
||||
m_dataBuffer[0x1f] = ((ourEntry->size >> 16) & 0xff);
|
||||
m_dataBuffer[0x20] = ((ourEntry->size >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
else // not a file or directory, recurse and hope the next one's better
|
||||
{
|
||||
return generateNextDirEntry();
|
||||
}
|
||||
|
||||
m_dataLen = 32;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ch376_device::doNextFileRead()
|
||||
{
|
||||
int lenToRead = (m_readLen >= 255) ? 255 : m_readLen;
|
||||
u32 actualRead;
|
||||
|
||||
m_readLen -= lenToRead;
|
||||
m_file->read(&m_dataBuffer[1], m_file_pos, lenToRead, actualRead);
|
||||
m_dataBuffer[0] = (lenToRead & 0xff);
|
||||
m_file_pos += actualRead;
|
||||
m_dataLen = 256;
|
||||
m_dataPtr = 0;
|
||||
}
|
80
src/devices/machine/ch376.h
Normal file
80
src/devices/machine/ch376.h
Normal file
@ -0,0 +1,80 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/***************************************************************************
|
||||
|
||||
ch376.h
|
||||
|
||||
"File manage and control chip CH376"
|
||||
This is a module intended to offload USB and USB mass storage
|
||||
I/O from a small microcontroller or microprocessor.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_MACHINE_CH376_H
|
||||
#define MAME_MACHINE_CH376_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
// ======================> ch376_device
|
||||
|
||||
class ch376_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
ch376_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
|
||||
u8 read(offs_t offset);
|
||||
void write(offs_t offset, u8 data);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
STATE_IDLE = 0,
|
||||
STATE_USB_MODE_SET,
|
||||
STATE_GET_STATUS,
|
||||
STATE_SET_FILE_NAME,
|
||||
STATE_SEEK,
|
||||
STATE_SEEK1,
|
||||
STATE_SEEK2,
|
||||
STATE_SEEK3,
|
||||
STATE_READ_SIZE,
|
||||
STATE_READ_SIZE2,
|
||||
STATE_WRITE_SIZE_REPLY,
|
||||
STATE_READ_WRITE_DATA,
|
||||
STATE_GET_FILE_SIZE
|
||||
};
|
||||
|
||||
bool generateNextDirEntry();
|
||||
void doNextFileRead();
|
||||
|
||||
int m_state;
|
||||
u8 m_status, m_int_status, m_data, m_last_command;
|
||||
char m_file_name[16];
|
||||
int m_pointer;
|
||||
std::string m_current_directory;
|
||||
osd::directory::ptr m_directory;
|
||||
osd_file::ptr m_file;
|
||||
u32 m_file_pos;
|
||||
|
||||
u8 m_dataBuffer[512];
|
||||
int m_dataPtr, m_dataLen;
|
||||
u16 m_readLen;
|
||||
u32 m_cur_file_size;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(CH376, ch376_device)
|
||||
|
||||
#endif // MAME_MACHINE_CH376_H
|
@ -168,6 +168,7 @@ MIG RAM page 2 $CE02 is the speaker/slot bitfield and $CE03 is the paddle/accele
|
||||
#include "bus/a2bus/a2videoterm.h"
|
||||
#include "bus/a2bus/a2vulcan.h"
|
||||
#include "bus/a2bus/a2zipdrive.h"
|
||||
#include "bus/a2bus/booti.h"
|
||||
#include "bus/a2bus/byte8251.h"
|
||||
#include "bus/a2bus/cmsscsi.h"
|
||||
#include "bus/a2bus/computereyes2.h"
|
||||
@ -4694,6 +4695,7 @@ static void apple2_cards(device_slot_interface &device)
|
||||
device.option_add("sider1", A2BUS_SIDER1); /* Advanced Tech Systems / First Class Peripherals Sider 1 SASI card */
|
||||
device.option_add("uniprint", A2BUS_UNIPRINT); /* Videx Uniprint parallel printer card */
|
||||
device.option_add("ccs7710", A2BUS_CCS7710); /* California Computer Systems Model 7710 Asynchronous Serial Interface */
|
||||
device.option_add("booti", A2BUS_BOOTI); /* Booti Card */
|
||||
}
|
||||
|
||||
static void apple2eaux_cards(device_slot_interface &device)
|
||||
|
@ -124,6 +124,7 @@
|
||||
#include "bus/a2bus/timemasterho.h"
|
||||
#include "bus/a2bus/uniprint.h"
|
||||
#include "bus/a2bus/uthernet.h"
|
||||
#include "bus/a2bus/booti.h"
|
||||
|
||||
#include "bus/a2gameio/gameio.h"
|
||||
|
||||
@ -4771,6 +4772,7 @@ static void apple2_cards(device_slot_interface &device)
|
||||
device.option_add("sider1", A2BUS_SIDER1); /* Advanced Tech Systems / First Class Peripherals Sider 1 SASI card */
|
||||
device.option_add("uniprint", A2BUS_UNIPRINT); /* Videx Uniprint parallel printer card */
|
||||
device.option_add("ccs7710", A2BUS_CCS7710); /* California Computer Systems Model 7710 Asynchronous Serial Interface */
|
||||
device.option_add("booti", A2BUS_BOOTI); /* Booti Card */
|
||||
}
|
||||
|
||||
void apple2gs_state::apple2gs(machine_config &config)
|
||||
|
Loading…
Reference in New Issue
Block a user