mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03:00
(MESS) Apple 1: Added support for expansion slot, moved cassette interface to a card to match reality. [R. Belmont]
This commit is contained in:
parent
ee6e952772
commit
ee918601db
4
.gitattributes
vendored
4
.gitattributes
vendored
@ -388,6 +388,10 @@ src/emu/attotime.c svneol=native#text/plain
|
||||
src/emu/attotime.h svneol=native#text/plain
|
||||
src/emu/audit.c svneol=native#text/plain
|
||||
src/emu/audit.h svneol=native#text/plain
|
||||
src/emu/bus/a1bus/a1bus.c svneol=native#text/plain
|
||||
src/emu/bus/a1bus/a1bus.h svneol=native#text/plain
|
||||
src/emu/bus/a1bus/a1cassette.c svneol=native#text/plain
|
||||
src/emu/bus/a1bus/a1cassette.h svneol=native#text/plain
|
||||
src/emu/bus/a2bus/a2alfam2.c svneol=native#text/plain
|
||||
src/emu/bus/a2bus/a2alfam2.h svneol=native#text/plain
|
||||
src/emu/bus/a2bus/a2applicard.c svneol=native#text/plain
|
||||
|
206
src/emu/bus/a1bus/a1bus.c
Normal file
206
src/emu/bus/a1bus/a1bus.c
Normal file
@ -0,0 +1,206 @@
|
||||
/***************************************************************************
|
||||
|
||||
a1bus.c - Apple I slot bus and card emulation
|
||||
|
||||
license: BSD-3-Clause
|
||||
copyright-holders: R. Belmont
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "emuopts.h"
|
||||
#include "a1bus.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
const device_type A1BUS_SLOT = &device_creator<a1bus_slot_device>;
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// a1bus_slot_device - constructor
|
||||
//-------------------------------------------------
|
||||
a1bus_slot_device::a1bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, A1BUS_SLOT, "Apple I Slot", tag, owner, clock, "a1bus_slot", __FILE__),
|
||||
device_slot_interface(mconfig, *this)
|
||||
{
|
||||
}
|
||||
|
||||
a1bus_slot_device::a1bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
|
||||
device_t(mconfig, type, name, tag, owner, clock, shortname, source),
|
||||
device_slot_interface(mconfig, *this)
|
||||
{
|
||||
}
|
||||
|
||||
void a1bus_slot_device::static_set_a1bus_slot(device_t &device, const char *tag, const char *slottag)
|
||||
{
|
||||
a1bus_slot_device &a1bus_card = dynamic_cast<a1bus_slot_device &>(device);
|
||||
a1bus_card.m_a1bus_tag = tag;
|
||||
a1bus_card.m_a1bus_slottag = slottag;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void a1bus_slot_device::device_start()
|
||||
{
|
||||
device_a1bus_card_interface *dev = dynamic_cast<device_a1bus_card_interface *>(get_card_device());
|
||||
|
||||
if (dev) device_a1bus_card_interface::static_set_a1bus_tag(*dev, m_a1bus_tag, m_a1bus_slottag);
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
const device_type A1BUS = &device_creator<a1bus_device>;
|
||||
|
||||
void a1bus_device::static_set_cputag(device_t &device, const char *tag)
|
||||
{
|
||||
a1bus_device &a1bus = downcast<a1bus_device &>(device);
|
||||
a1bus.m_cputag = tag;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// a1bus_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
a1bus_device::a1bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, A1BUS, "Apple I Bus", tag, owner, clock, "a1bus", __FILE__),
|
||||
m_out_irq_cb(*this),
|
||||
m_out_nmi_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
a1bus_device::a1bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
|
||||
device_t(mconfig, type, name, tag, owner, clock, shortname, source),
|
||||
m_out_irq_cb(*this),
|
||||
m_out_nmi_cb(*this)
|
||||
{
|
||||
}
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void a1bus_device::device_start()
|
||||
{
|
||||
m_maincpu = machine().device<cpu_device>(m_cputag);
|
||||
|
||||
// resolve callbacks
|
||||
m_out_irq_cb.resolve_safe();
|
||||
m_out_nmi_cb.resolve_safe();
|
||||
|
||||
// clear slot
|
||||
m_device = NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void a1bus_device::device_reset()
|
||||
{
|
||||
}
|
||||
|
||||
device_a1bus_card_interface *a1bus_device::get_a1bus_card()
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
void a1bus_device::add_a1bus_card(device_a1bus_card_interface *card)
|
||||
{
|
||||
m_device = card;
|
||||
}
|
||||
|
||||
void a1bus_device::set_irq_line(int state)
|
||||
{
|
||||
m_out_irq_cb(state);
|
||||
}
|
||||
|
||||
void a1bus_device::set_nmi_line(int state)
|
||||
{
|
||||
m_out_nmi_cb(state);
|
||||
}
|
||||
|
||||
void a1bus_device::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler)
|
||||
{
|
||||
m_maincpu = machine().device<cpu_device>(m_cputag);
|
||||
|
||||
m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler);
|
||||
}
|
||||
|
||||
void a1bus_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data)
|
||||
{
|
||||
// printf("install_bank: %s @ %x->%x mask %x mirror %x\n", tag, start, end, mask, mirror);
|
||||
m_maincpu = machine().device<cpu_device>(m_cputag);
|
||||
address_space &space = m_maincpu->space(AS_PROGRAM);
|
||||
space.install_readwrite_bank(start, end, mask, mirror, tag );
|
||||
machine().root_device().membank(tag)->set_base(data);
|
||||
}
|
||||
|
||||
// interrupt request from a1bus card
|
||||
WRITE_LINE_MEMBER( a1bus_device::irq_w ) { m_out_irq_cb(state); }
|
||||
WRITE_LINE_MEMBER( a1bus_device::nmi_w ) { m_out_nmi_cb(state); }
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE CONFIG A1BUS CARD INTERFACE
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE A1BUS CARD INTERFACE
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_a1bus_card_interface - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_a1bus_card_interface::device_a1bus_card_interface(const machine_config &mconfig, device_t &device)
|
||||
: device_slot_card_interface(mconfig, device),
|
||||
m_a1bus(NULL),
|
||||
m_a1bus_tag(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ~device_a1bus_card_interface - destructor
|
||||
//-------------------------------------------------
|
||||
|
||||
device_a1bus_card_interface::~device_a1bus_card_interface()
|
||||
{
|
||||
}
|
||||
|
||||
void device_a1bus_card_interface::static_set_a1bus_tag(device_t &device, const char *tag, const char *slottag)
|
||||
{
|
||||
device_a1bus_card_interface &a1bus_card = dynamic_cast<device_a1bus_card_interface &>(device);
|
||||
a1bus_card.m_a1bus_tag = tag;
|
||||
a1bus_card.m_a1bus_slottag = slottag;
|
||||
}
|
||||
|
||||
void device_a1bus_card_interface::set_a1bus_device()
|
||||
{
|
||||
m_a1bus = dynamic_cast<a1bus_device *>(device().machine().device(m_a1bus_tag));
|
||||
m_a1bus->add_a1bus_card(this);
|
||||
}
|
||||
|
||||
void device_a1bus_card_interface::install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler)
|
||||
{
|
||||
m_a1bus->install_device(start, end, rhandler, whandler);
|
||||
}
|
||||
|
||||
void device_a1bus_card_interface::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, char *tag, UINT8 *data)
|
||||
{
|
||||
m_a1bus->install_bank(start, end, mask, mirror, tag, data);
|
||||
}
|
||||
|
146
src/emu/bus/a1bus/a1bus.h
Normal file
146
src/emu/bus/a1bus/a1bus.h
Normal file
@ -0,0 +1,146 @@
|
||||
/***************************************************************************
|
||||
|
||||
a1bus.h - Apple I expansion slot and card emulation
|
||||
|
||||
license: BSD-3-Clause
|
||||
copyright-holders: R. Belmont
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __A1BUS_H__
|
||||
#define __A1BUS_H__
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
//**************************************************************************
|
||||
// INTERFACE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define MCFG_A1BUS_CPU(_cputag) \
|
||||
a1bus_device::static_set_cputag(*device, _cputag);
|
||||
|
||||
#define MCFG_A1BUS_OUT_IRQ_CB(_devcb) \
|
||||
devcb = &a1bus_device::set_out_irq_callback(*device, DEVCB2_##_devcb);
|
||||
|
||||
#define MCFG_A1BUS_OUT_NMI_CB(_devcb) \
|
||||
devcb = &a1bus_device::set_out_nmi_callback(*device, DEVCB2_##_devcb);
|
||||
|
||||
#define MCFG_A1BUS_SLOT_ADD(_nbtag, _tag, _slot_intf, _def_slot) \
|
||||
MCFG_DEVICE_ADD(_tag, A1BUS_SLOT, 0) \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \
|
||||
a1bus_slot_device::static_set_a1bus_slot(*device, _nbtag, _tag);
|
||||
#define MCFG_A1BUS_SLOT_REMOVE(_tag) \
|
||||
MCFG_DEVICE_REMOVE(_tag)
|
||||
|
||||
#define MCFG_A1BUS_ONBOARD_ADD(_nbtag, _tag, _dev_type, _def_inp) \
|
||||
MCFG_DEVICE_ADD(_tag, _dev_type, 0) \
|
||||
MCFG_DEVICE_INPUT_DEFAULTS(_def_inp) \
|
||||
device_a1bus_card_interface::static_set_a1bus_tag(*device, _nbtag, _tag);
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
class a1bus_device;
|
||||
|
||||
class a1bus_slot_device : public device_t,
|
||||
public device_slot_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a1bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
a1bus_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
|
||||
// inline configuration
|
||||
static void static_set_a1bus_slot(device_t &device, const char *tag, const char *slottag);
|
||||
protected:
|
||||
// configuration
|
||||
const char *m_a1bus_tag, *m_a1bus_slottag;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type A1BUS_SLOT;
|
||||
|
||||
|
||||
class device_a1bus_card_interface;
|
||||
// ======================> a1bus_device
|
||||
class a1bus_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a1bus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
a1bus_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
|
||||
// inline configuration
|
||||
static void static_set_cputag(device_t &device, const char *tag);
|
||||
template<class _Object> static devcb2_base &set_out_irq_callback(device_t &device, _Object object) { return downcast<a1bus_device &>(device).m_out_irq_cb.set_callback(object); }
|
||||
template<class _Object> static devcb2_base &set_out_nmi_callback(device_t &device, _Object object) { return downcast<a1bus_device &>(device).m_out_nmi_cb.set_callback(object); }
|
||||
|
||||
void add_a1bus_card(device_a1bus_card_interface *card);
|
||||
device_a1bus_card_interface *get_a1bus_card();
|
||||
|
||||
void set_irq_line(int state);
|
||||
void set_nmi_line(int state);
|
||||
|
||||
void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler);
|
||||
void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( irq_w );
|
||||
DECLARE_WRITE_LINE_MEMBER( nmi_w );
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
// internal state
|
||||
cpu_device *m_maincpu;
|
||||
|
||||
devcb2_write_line m_out_irq_cb;
|
||||
devcb2_write_line m_out_nmi_cb;
|
||||
|
||||
device_a1bus_card_interface *m_device;
|
||||
const char *m_cputag;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
extern const device_type A1BUS;
|
||||
|
||||
// ======================> device_a1bus_card_interface
|
||||
|
||||
// class representing interface-specific live a1bus card
|
||||
class device_a1bus_card_interface : public device_slot_card_interface
|
||||
{
|
||||
friend class a1bus_device;
|
||||
public:
|
||||
// construction/destruction
|
||||
device_a1bus_card_interface(const machine_config &mconfig, device_t &device);
|
||||
virtual ~device_a1bus_card_interface();
|
||||
|
||||
device_a1bus_card_interface *next() const { return m_next; }
|
||||
|
||||
void set_a1bus_device();
|
||||
|
||||
void raise_slot_irq() { m_a1bus->set_irq_line(ASSERT_LINE); }
|
||||
void lower_slot_irq() { m_a1bus->set_irq_line(CLEAR_LINE); }
|
||||
void raise_slot_nmi() { m_a1bus->set_nmi_line(ASSERT_LINE); }
|
||||
void lower_slot_nmi() { m_a1bus->set_nmi_line(CLEAR_LINE); }
|
||||
|
||||
void install_device(offs_t start, offs_t end, read8_delegate rhandler, write8_delegate whandler);
|
||||
void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, char *tag, UINT8 *data);
|
||||
|
||||
// inline configuration
|
||||
static void static_set_a1bus_tag(device_t &device, const char *tag, const char *slottag);
|
||||
public:
|
||||
a1bus_device *m_a1bus;
|
||||
const char *m_a1bus_tag, *m_a1bus_slottag;
|
||||
device_a1bus_card_interface *m_next;
|
||||
};
|
||||
|
||||
#endif /* __A1BUS_H__ */
|
206
src/emu/bus/a1bus/a1cassette.c
Normal file
206
src/emu/bus/a1bus/a1cassette.c
Normal file
@ -0,0 +1,206 @@
|
||||
/*********************************************************************
|
||||
|
||||
a1cassette.c
|
||||
|
||||
Apple I Cassette Interface
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "a1cassette.h"
|
||||
|
||||
/***************************************************************************
|
||||
PARAMETERS
|
||||
***************************************************************************/
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
#define CASSETTE_ROM_REGION "casrom"
|
||||
|
||||
const device_type A1BUS_CASSETTE = &device_creator<a1bus_cassette_device>;
|
||||
|
||||
/* sound output */
|
||||
|
||||
static const cassette_interface apple1_cassette_interface =
|
||||
{
|
||||
cassette_default_formats,
|
||||
NULL,
|
||||
(cassette_state)(CASSETTE_STOPPED),
|
||||
"apple1_cass",
|
||||
NULL
|
||||
};
|
||||
|
||||
MACHINE_CONFIG_FRAGMENT( cassette )
|
||||
MCFG_CASSETTE_ADD("cassette", apple1_cassette_interface)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
ROM_START( cassette )
|
||||
/* 256-byte cassette interface ROM, in two 82s129 or mmi6301 256x4 proms at locations 3 and 4 on the cassette interface daughtercard (they are labeled "MMI 6301-IJ // 7623L // APPLE-A3" and "MMI 6301-IJ // 7623L // APPLE-A4") */
|
||||
ROM_REGION(0x100, CASSETTE_ROM_REGION, 0)
|
||||
ROM_LOAD_NIB_HIGH( "apple-a3.3", 0x0000, 0x0100, CRC(6eae8f52) SHA1(71906932727ef70952ef6afe6b08708df15cd67d) )
|
||||
ROM_LOAD_NIB_LOW( "apple-a4.4", 0x0000, 0x0100, CRC(94efa977) SHA1(851f3bd6863859a1a6909179a5e5bf744b3d807e) )
|
||||
ROM_END
|
||||
|
||||
//-------------------------------------------------
|
||||
// machine_config_additions - device-specific
|
||||
// machine configurations
|
||||
//-------------------------------------------------
|
||||
|
||||
machine_config_constructor a1bus_cassette_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( cassette );
|
||||
}
|
||||
|
||||
const rom_entry *a1bus_cassette_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( cassette );
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// LIVE DEVICE
|
||||
//**************************************************************************
|
||||
|
||||
a1bus_cassette_device::a1bus_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
||||
device_t(mconfig, A1BUS_CASSETTE, "Apple I cassette board", tag, owner, clock, "a1cass", __FILE__),
|
||||
device_a1bus_card_interface(mconfig, *this),
|
||||
m_cassette(*this, "cassette")
|
||||
{
|
||||
}
|
||||
|
||||
a1bus_cassette_device::a1bus_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
|
||||
device_t(mconfig, type, name, tag, owner, clock, shortname, source),
|
||||
device_a1bus_card_interface(mconfig, *this),
|
||||
m_cassette(*this, "cassette")
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void a1bus_cassette_device::device_start()
|
||||
{
|
||||
set_a1bus_device();
|
||||
|
||||
astring tempstring;
|
||||
m_rom = device().machine().root_device().memregion(this->subtag(tempstring, CASSETTE_ROM_REGION))->base();
|
||||
|
||||
install_device(0xc000, 0xc0ff, read8_delegate(FUNC(a1bus_cassette_device::cassette_r), this), write8_delegate(FUNC(a1bus_cassette_device::cassette_w), this));
|
||||
install_bank(0xc100, 0xc1ff, 0, 0, (char *)"bank_a1cas", m_rom);
|
||||
}
|
||||
|
||||
void a1bus_cassette_device::device_reset()
|
||||
{
|
||||
m_cassette_output_flipflop = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
** Cassette interface I/O
|
||||
**
|
||||
** The Apple I's cassette interface was a small card that plugged
|
||||
** into the expansion connector on the motherboard. (This was a
|
||||
** slot-type connector, separate from the motherboard's edge
|
||||
** connector, but with the same signals.) The cassette interface
|
||||
** provided separate cassette input and output jacks, some very
|
||||
** simple interface hardware, and 256 bytes of ROM containing the
|
||||
** cassette I/O code.
|
||||
**
|
||||
** The interface was mostly software-controlled. The only hardware
|
||||
** was an output flip-flop for generating the cassette output signal,
|
||||
** a National Semiconductor LM311 voltage comparator for generating a
|
||||
** digital signal from the analog cassette input, an input
|
||||
** signal-level LED, and some gates to control the interface logic
|
||||
** and address decoding. The cassette ROM code did most of the work
|
||||
** of generating and interpreting tape signals. It also contained
|
||||
** its own mini-monitor for issuing tape read and write commands.
|
||||
**
|
||||
** The cassette interface was assigned to the $C000-$CFFF block of
|
||||
** addresses, although it did not use most of the space in that
|
||||
** block. Addresses were mapped as follows:
|
||||
**
|
||||
** $C000-$C0FF: Cassette I/O space.
|
||||
** Any access here toggles the output signal.
|
||||
** $C000-$C07F: Cassette output only; input disabled.
|
||||
** Mirrors $C100-$C17F on reads.
|
||||
** $C080-$C0FF: Cassette input and output.
|
||||
** When input low, mirrors $C180-$C1FF on reads.
|
||||
** When input high, both odd and even addresses
|
||||
** mirror even ROM addresses $C180-$C1FE.
|
||||
** $C100-$C1FF: Cassette ROM code.
|
||||
**
|
||||
** Note the peculiar addressing scheme. Data was written simply
|
||||
** through repeated accesses, rather than by writing to an address.
|
||||
** Data was read by reading an odd input address and comparing the
|
||||
** ROM byte returned to detect signal changes.
|
||||
**
|
||||
** The standard tape signal was a simple square wave, although this
|
||||
** was often greatly distorted by the cassette recorder. A single
|
||||
** tape record consisted of a 10-second 800-Hz leader, followed by a
|
||||
** single short square-wave cycle used as a sync bit, followed by the
|
||||
** tape data. The data was encoded using a single square-wave cycle
|
||||
** for each bit; "1" bits were at 1000 Hz, "0" bits at 2000 Hz. (All
|
||||
** of these frequencies are approximate and could vary due to
|
||||
** differences in recorder speed.) Each byte was written starting
|
||||
** from the most significant bit; bytes were written from low to high
|
||||
** addresses. No error detection was provided. Multiple records
|
||||
** could be placed on a single tape.
|
||||
*****************************************************************************/
|
||||
|
||||
/* The cassette output signal for writing tapes is generated by a
|
||||
flip-flop which is toggled to produce the output waveform. Any
|
||||
access to the cassette I/O range, whether a read or a write,
|
||||
toggles this flip-flop. */
|
||||
void a1bus_cassette_device::cassette_toggle_output()
|
||||
{
|
||||
m_cassette_output_flipflop = !m_cassette_output_flipflop;
|
||||
m_cassette->output(m_cassette_output_flipflop ? 1.0 : -1.0);
|
||||
}
|
||||
|
||||
READ8_MEMBER(a1bus_cassette_device::cassette_r)
|
||||
{
|
||||
cassette_toggle_output();
|
||||
|
||||
if (offset <= 0x7f)
|
||||
{
|
||||
/* If the access is to address range $C000-$C07F, the cassette
|
||||
input signal is ignored . In this case the value read
|
||||
always comes from the corresponding cassette ROM location
|
||||
in $C100-$C17F. */
|
||||
|
||||
return m_rom[offset];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For accesses to address range $C080-$C0FF, the cassette
|
||||
input signal is enabled. If the signal is low, the value
|
||||
read comes from the corresponding cassette ROM location in
|
||||
$C180-$C1FF. If the signal is high, the low bit of the
|
||||
address is masked before the corresponding cassette ROM
|
||||
location is accessed; e.g., a read from $C081 would return
|
||||
the ROM byte at $C180. The cassette ROM routines detect
|
||||
changes in the cassette input signal by repeatedly reading
|
||||
from $C081 and comparing the values read. */
|
||||
|
||||
/* (Don't try putting a non-zero "noise threshhold" here,
|
||||
because it can cause tape header bits on real cassette
|
||||
images to be misread as data bits.) */
|
||||
if (m_cassette->input() > 0.0)
|
||||
return m_rom[0xc100 + (offset & ~1)];
|
||||
else
|
||||
return m_rom[0xc100 + offset];
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(a1bus_cassette_device::cassette_w)
|
||||
{
|
||||
/* Writes toggle the output flip-flop in the same way that reads
|
||||
do; other than that they have no effect. Any repeated accesses
|
||||
to the cassette I/O address range can be used to write data to
|
||||
cassette, and the cassette ROM always uses reads to do this.
|
||||
However, we still have to handle writes, since they may be done
|
||||
by user code. */
|
||||
|
||||
cassette_toggle_output();
|
||||
}
|
||||
|
51
src/emu/bus/a1bus/a1cassette.h
Normal file
51
src/emu/bus/a1bus/a1cassette.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*********************************************************************
|
||||
|
||||
a1cassette.h
|
||||
|
||||
Apple II 6850 MIDI card, as made by Passport, Yamaha, and others.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef __A1BUS_CASSETTE__
|
||||
#define __A1BUS_CASSETTE__
|
||||
|
||||
#include "a1bus.h"
|
||||
#include "imagedev/cassette.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
class a1bus_cassette_device:
|
||||
public device_t,
|
||||
public device_a1bus_card_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
a1bus_cassette_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
a1bus_cassette_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
|
||||
// optional information overrides
|
||||
virtual machine_config_constructor device_mconfig_additions() const;
|
||||
virtual const rom_entry *device_rom_region() const;
|
||||
|
||||
optional_device<cassette_image_device> m_cassette;
|
||||
|
||||
DECLARE_READ8_MEMBER(cassette_r);
|
||||
DECLARE_WRITE8_MEMBER(cassette_w);
|
||||
|
||||
protected:
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
void cassette_toggle_output();
|
||||
|
||||
private:
|
||||
UINT8 *m_rom;
|
||||
int m_cassette_output_flipflop;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type A1BUS_CASSETTE;
|
||||
|
||||
#endif /* __A1BUS_CASSETTE__ */
|
@ -1066,3 +1066,15 @@ BUSOBJS += $(BUSOBJ)/oricext/oricext.o
|
||||
BUSOBJS += $(BUSOBJ)/oricext/jasmin.o
|
||||
BUSOBJS += $(BUSOBJ)/oricext/microdisc.o
|
||||
endif
|
||||
|
||||
#-------------------------------------------------
|
||||
#
|
||||
#@src/emu/bus/a1bus/a1bus.h,BUSES += A1BUS
|
||||
#-------------------------------------------------
|
||||
|
||||
ifneq ($(filter A1BUS,$(BUSES)),)
|
||||
OBJDIRS += $(BUSOBJ)/a1bus
|
||||
BUSOBJS += $(BUSOBJ)/a1bus/a1bus.o
|
||||
BUSOBJS += $(BUSOBJ)/a1bus/a1cassette.o
|
||||
endif
|
||||
|
||||
|
@ -129,30 +129,21 @@ When the prompt returns, press Stop.
|
||||
#include "machine/6821pia.h"
|
||||
#include "includes/apple1.h"
|
||||
#include "imagedev/snapquik.h"
|
||||
#include "imagedev/cassette.h"
|
||||
#include "machine/ram.h"
|
||||
|
||||
#include "bus/a1bus/a1bus.h"
|
||||
#include "bus/a1bus/a1cassette.h"
|
||||
|
||||
/* port i/o functions */
|
||||
|
||||
/* memory w/r functions */
|
||||
|
||||
static ADDRESS_MAP_START( apple1_map, AS_PROGRAM, 8, apple1_state )
|
||||
AM_RANGE(0x0000, 0xbfff) AM_NOP
|
||||
|
||||
/* Cassette interface I/O space: */
|
||||
AM_RANGE(0xc000, 0xc0ff) AM_READWRITE(apple1_cassette_r, apple1_cassette_w)
|
||||
/* Cassette interface ROM: */
|
||||
AM_RANGE(0xc100, 0xc1ff) AM_ROM
|
||||
|
||||
AM_RANGE(0xc200, 0xcfff) AM_NOP
|
||||
|
||||
/* In $D000-$DFFF, PIA is selected by address bit 4 being high,
|
||||
and PIA registers are addressed with address bits 0-1. All
|
||||
other address bits are ignored. Thus $D010-$D013 is mirrored
|
||||
at all $Dxxx addresses with bit 4 high. */
|
||||
AM_RANGE(0xd010, 0xd013) AM_MIRROR(0x0fec) AM_DEVREADWRITE("pia",pia6821_device, read, write)
|
||||
/* $Dxxx addresses with bit 4 low are NOPs. */
|
||||
AM_RANGE(0xd000, 0xd00f) AM_NOP AM_MIRROR(0xfe0)
|
||||
|
||||
/* We always include the remapped RAM for cassette BASIC, both for
|
||||
simplicity and to allow the running of BASIC programs. */
|
||||
@ -161,7 +152,7 @@ static ADDRESS_MAP_START( apple1_map, AS_PROGRAM, 8, apple1_state )
|
||||
AM_RANGE(0xf000, 0xfeff) AM_NOP
|
||||
|
||||
/* Monitor ROM: */
|
||||
AM_RANGE(0xff00, 0xffff) AM_ROM
|
||||
AM_RANGE(0xff00, 0xffff) AM_ROM AM_REGION("maincpu", 0)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
/* graphics output */
|
||||
@ -264,16 +255,9 @@ static INPUT_PORTS_START( apple1 )
|
||||
PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Clear") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
|
||||
INPUT_PORTS_END
|
||||
|
||||
/* sound output */
|
||||
|
||||
static const cassette_interface apple1_cassette_interface =
|
||||
{
|
||||
cassette_default_formats,
|
||||
NULL,
|
||||
(cassette_state)(CASSETTE_STOPPED),
|
||||
"apple1_cass",
|
||||
NULL
|
||||
};
|
||||
static SLOT_INTERFACE_START(apple1_cards)
|
||||
SLOT_INTERFACE("cassette", A1BUS_CASSETTE)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
/* machine definition */
|
||||
static MACHINE_CONFIG_START( apple1, apple1_state )
|
||||
@ -309,10 +293,13 @@ static MACHINE_CONFIG_START( apple1, apple1_state )
|
||||
MCFG_PIA_WRITEPB_HANDLER(WRITE8(apple1_state,apple1_pia0_dspout))
|
||||
MCFG_PIA_CB2_HANDLER(WRITELINE(apple1_state,apple1_pia0_dsp_write_signal))
|
||||
|
||||
MCFG_DEVICE_ADD("a1bus", A1BUS, 0)
|
||||
MCFG_A1BUS_CPU("maincpu")
|
||||
MCFG_A1BUS_SLOT_ADD("a1bus", "exp", apple1_cards, "cassette")
|
||||
|
||||
/* snapshot */
|
||||
MCFG_SNAPSHOT_ADD("snapshot", apple1_state, apple1, "snp", 0)
|
||||
|
||||
MCFG_CASSETTE_ADD("cassette", apple1_cassette_interface)
|
||||
MCFG_SOFTWARE_LIST_ADD("cass_list","apple1")
|
||||
|
||||
/* Note that because we always include 4K of RAM at $E000-$EFFF,
|
||||
@ -326,13 +313,10 @@ static MACHINE_CONFIG_START( apple1, apple1_state )
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
ROM_START(apple1)
|
||||
ROM_REGION(0x10000, "maincpu",0)
|
||||
ROM_REGION(0x100, "maincpu",0)
|
||||
/* 256-byte main monitor ROM, in two 82s129 or mmi6301 256x4 proms at A1 and A2 called APPLE-A1(bits D3-D0) and APPLE-A2(bits D7-D4) */
|
||||
ROM_LOAD_NIB_HIGH( "apple-a2.a2", 0xFF00, 0x0100, CRC(254bfb95) SHA1(b6468b72295b7d8ac288d104d252f24de1f1d611) )
|
||||
ROM_LOAD_NIB_LOW( "apple-a1.a1", 0xFF00, 0x0100, CRC(434f8ce6) SHA1(9deee2d39903209b20c3fc6b58e16372f8efece1) )
|
||||
/* 256-byte cassette interface ROM, in two 82s129 or mmi6301 256x4 proms at locations 3 and 4 on the cassette interface daughtercard (they are labeled "MMI 6301-IJ // 7623L // APPLE-A3" and "MMI 6301-IJ // 7623L // APPLE-A4") */
|
||||
ROM_LOAD_NIB_HIGH( "apple-a3.3", 0xc100, 0x0100, CRC(6eae8f52) SHA1(71906932727ef70952ef6afe6b08708df15cd67d) )
|
||||
ROM_LOAD_NIB_LOW( "apple-a4.4", 0xc100, 0x0100, CRC(94efa977) SHA1(851f3bd6863859a1a6909179a5e5bf744b3d807e) )
|
||||
ROM_LOAD_NIB_HIGH( "apple-a2.a2", 0x0000, 0x0100, CRC(254bfb95) SHA1(b6468b72295b7d8ac288d104d252f24de1f1d611) )
|
||||
ROM_LOAD_NIB_LOW( "apple-a1.a1", 0x0000, 0x0100, CRC(434f8ce6) SHA1(9deee2d39903209b20c3fc6b58e16372f8efece1) )
|
||||
/* 512-byte Signetics 2513 character generator ROM at location D2-D3 */
|
||||
ROM_REGION(0x0200, "gfx1",0)
|
||||
ROM_LOAD("s2513.d2", 0x0000, 0x0200, CRC(a7e567fc) SHA1(b18aae0a2d4f92f5a7e22640719bbc4652f3f4ee)) // apple1.vid
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define APPLE1_H_
|
||||
|
||||
#include "imagedev/snapquik.h"
|
||||
#include "imagedev/cassette.h"
|
||||
#include "machine/ram.h"
|
||||
|
||||
typedef short termchar_t;
|
||||
@ -34,7 +33,6 @@ public:
|
||||
apple1_state(const machine_config &mconfig, device_type type, const char *tag)
|
||||
: driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_cassette(*this, "cassette"),
|
||||
m_ram(*this, RAM_TAG),
|
||||
m_gfxdecode(*this, "gfxdecode"),
|
||||
m_screen(*this, "screen") { }
|
||||
@ -43,12 +41,9 @@ public:
|
||||
int m_kbd_data;
|
||||
UINT32 m_kbd_last_scan[4];
|
||||
int m_reset_flag;
|
||||
int m_cassette_output_flipflop;
|
||||
terminal_t *m_current_terminal;
|
||||
terminal_t *m_terminal;
|
||||
int m_blink_on;
|
||||
DECLARE_READ8_MEMBER(apple1_cassette_r);
|
||||
DECLARE_WRITE8_MEMBER(apple1_cassette_w);
|
||||
DECLARE_DRIVER_INIT(apple1);
|
||||
TILE_GET_INFO_MEMBER(terminal_gettileinfo);
|
||||
virtual void machine_reset();
|
||||
@ -62,7 +57,6 @@ public:
|
||||
DECLARE_WRITE8_MEMBER(apple1_pia0_dspout);
|
||||
DECLARE_WRITE_LINE_MEMBER(apple1_pia0_dsp_write_signal);
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<cassette_image_device> m_cassette;
|
||||
void terminal_draw(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, terminal_t *terminal);
|
||||
void verify_coords(terminal_t *terminal, int x, int y);
|
||||
void terminal_putchar(terminal_t *terminal, int x, int y, int ch);
|
||||
@ -79,7 +73,6 @@ public:
|
||||
void apple1_vh_dsp_clr ();
|
||||
void apple1_vh_cursor_blink ();
|
||||
int apple1_verify_header (UINT8 *data);
|
||||
void cassette_toggle_output();
|
||||
terminal_t *terminal_create(int gfx, int blank_char, int char_bits,int (*getcursorcode)(int original_code),int num_cols, int num_rows);
|
||||
attotime apple1_vh_dsp_time_to_ready();
|
||||
DECLARE_SNAPSHOT_LOAD_MEMBER( apple1 );
|
||||
|
@ -402,111 +402,3 @@ TIMER_CALLBACK_MEMBER(apple1_state::apple1_dsp_ready_end)
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Cassette interface I/O
|
||||
**
|
||||
** The Apple I's cassette interface was a small card that plugged
|
||||
** into the expansion connector on the motherboard. (This was a
|
||||
** slot-type connector, separate from the motherboard's edge
|
||||
** connector, but with the same signals.) The cassette interface
|
||||
** provided separate cassette input and output jacks, some very
|
||||
** simple interface hardware, and 256 bytes of ROM containing the
|
||||
** cassette I/O code.
|
||||
**
|
||||
** The interface was mostly software-controlled. The only hardware
|
||||
** was an output flip-flop for generating the cassette output signal,
|
||||
** a National Semiconductor LM311 voltage comparator for generating a
|
||||
** digital signal from the analog cassette input, an input
|
||||
** signal-level LED, and some gates to control the interface logic
|
||||
** and address decoding. The cassette ROM code did most of the work
|
||||
** of generating and interpreting tape signals. It also contained
|
||||
** its own mini-monitor for issuing tape read and write commands.
|
||||
**
|
||||
** The cassette interface was assigned to the $C000-$CFFF block of
|
||||
** addresses, although it did not use most of the space in that
|
||||
** block. Addresses were mapped as follows:
|
||||
**
|
||||
** $C000-$C0FF: Cassette I/O space.
|
||||
** Any access here toggles the output signal.
|
||||
** $C000-$C07F: Cassette output only; input disabled.
|
||||
** Mirrors $C100-$C17F on reads.
|
||||
** $C080-$C0FF: Cassette input and output.
|
||||
** When input low, mirrors $C180-$C1FF on reads.
|
||||
** When input high, both odd and even addresses
|
||||
** mirror even ROM addresses $C180-$C1FE.
|
||||
** $C100-$C1FF: Cassette ROM code.
|
||||
**
|
||||
** Note the peculiar addressing scheme. Data was written simply
|
||||
** through repeated accesses, rather than by writing to an address.
|
||||
** Data was read by reading an odd input address and comparing the
|
||||
** ROM byte returned to detect signal changes.
|
||||
**
|
||||
** The standard tape signal was a simple square wave, although this
|
||||
** was often greatly distorted by the cassette recorder. A single
|
||||
** tape record consisted of a 10-second 800-Hz leader, followed by a
|
||||
** single short square-wave cycle used as a sync bit, followed by the
|
||||
** tape data. The data was encoded using a single square-wave cycle
|
||||
** for each bit; "1" bits were at 1000 Hz, "0" bits at 2000 Hz. (All
|
||||
** of these frequencies are approximate and could vary due to
|
||||
** differences in recorder speed.) Each byte was written starting
|
||||
** from the most significant bit; bytes were written from low to high
|
||||
** addresses. No error detection was provided. Multiple records
|
||||
** could be placed on a single tape.
|
||||
*****************************************************************************/
|
||||
|
||||
/* The cassette output signal for writing tapes is generated by a
|
||||
flip-flop which is toggled to produce the output waveform. Any
|
||||
access to the cassette I/O range, whether a read or a write,
|
||||
toggles this flip-flop. */
|
||||
void apple1_state::cassette_toggle_output()
|
||||
{
|
||||
m_cassette_output_flipflop = !m_cassette_output_flipflop;
|
||||
m_cassette->output(m_cassette_output_flipflop ? 1.0 : -1.0);
|
||||
}
|
||||
|
||||
READ8_MEMBER(apple1_state::apple1_cassette_r)
|
||||
{
|
||||
cassette_toggle_output();
|
||||
|
||||
if (offset <= 0x7f)
|
||||
{
|
||||
/* If the access is to address range $C000-$C07F, the cassette
|
||||
input signal is ignored . In this case the value read
|
||||
always comes from the corresponding cassette ROM location
|
||||
in $C100-$C17F. */
|
||||
|
||||
return space.read_byte(0xc100 + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For accesses to address range $C080-$C0FF, the cassette
|
||||
input signal is enabled. If the signal is low, the value
|
||||
read comes from the corresponding cassette ROM location in
|
||||
$C180-$C1FF. If the signal is high, the low bit of the
|
||||
address is masked before the corresponding cassette ROM
|
||||
location is accessed; e.g., a read from $C081 would return
|
||||
the ROM byte at $C180. The cassette ROM routines detect
|
||||
changes in the cassette input signal by repeatedly reading
|
||||
from $C081 and comparing the values read. */
|
||||
|
||||
/* (Don't try putting a non-zero "noise threshhold" here,
|
||||
because it can cause tape header bits on real cassette
|
||||
images to be misread as data bits.) */
|
||||
if (m_cassette->input() > 0.0)
|
||||
return space.read_byte(0xc100 + (offset & ~1));
|
||||
else
|
||||
return space.read_byte(0xc100 + offset);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(apple1_state::apple1_cassette_w)
|
||||
{
|
||||
/* Writes toggle the output flip-flop in the same way that reads
|
||||
do; other than that they have no effect. Any repeated accesses
|
||||
to the cassette I/O address range can be used to write data to
|
||||
cassette, and the cassette ROM always uses reads to do this.
|
||||
However, we still have to handle writes, since they may be done
|
||||
by user code. */
|
||||
|
||||
cassette_toggle_output();
|
||||
}
|
||||
|
@ -520,6 +520,7 @@ MACHINES += WOZFDC
|
||||
# specify available bus cores
|
||||
#-------------------------------------------------
|
||||
|
||||
BUSES += A1BUS
|
||||
BUSES += A2BUS
|
||||
BUSES += ABCBUS
|
||||
BUSES += ABCKB
|
||||
|
Loading…
Reference in New Issue
Block a user