(nw) amu880: added a cassette interface

This commit is contained in:
Robbbert 2019-06-17 02:18:19 +10:00
parent 55e52efcd1
commit 7080aa92fd
2 changed files with 59 additions and 19 deletions

View File

@ -9,7 +9,7 @@
/* /*
TODO: TODO:
- keyboard repeat - keyboard repeat
- shift lock is not PORT_TOGGLE, instead RS flipflop - shift lock is not PORT_TOGGLE, instead RS flipflop
@ -18,10 +18,27 @@
- eprom programmer - eprom programmer
- power off - power off
Cassette considerations
- It operates at 4883 baud but may not be fully compatible with real
hardware. A partial translation of the available text seems to
indicate an overcomplicated and unreliable interface. The one
implemented is 100% reliable at the same speed. I've been unable
to locate any real recordings to compare against.
- To save a range of memory: S name start end
- To load it back: L name
- To save an unnamed file: S "" start end
- To load an unnamed file: L
- When loading, if the name doesn't match, there's no message, and no
way to determine the name.
- For some reason, the system saves the file 3 times. Maybe it was an
attempt to guard against the inherent unreliable design.
*/ */
#include "emu.h" #include "emu.h"
#include "includes/huebler.h" #include "includes/huebler.h"
#include "sound/wave.h"
#include "speaker.h"
#include "screen.h" #include "screen.h"
/* Keyboard */ /* Keyboard */
@ -103,7 +120,7 @@ void amu880_state::amu880_io(address_map &map)
map(0x0c, 0x0f).rw(Z80PIO2_TAG, FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt)); map(0x0c, 0x0f).rw(Z80PIO2_TAG, FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt));
map(0x10, 0x13).rw(Z80PIO1_TAG, FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt)); map(0x10, 0x13).rw(Z80PIO1_TAG, FUNC(z80pio_device::read_alt), FUNC(z80pio_device::write_alt));
map(0x14, 0x17).rw(Z80CTC_TAG, FUNC(z80ctc_device::read), FUNC(z80ctc_device::write)); map(0x14, 0x17).rw(Z80CTC_TAG, FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
map(0x18, 0x1b).rw(m_z80sio, FUNC(z80sio0_device::ba_cd_r), FUNC(z80sio0_device::ba_cd_w)); map(0x18, 0x1b).rw(m_sio, FUNC(z80sio0_device::ba_cd_r), FUNC(z80sio0_device::ba_cd_w));
} }
/* Input Ports */ /* Input Ports */
@ -252,19 +269,36 @@ WRITE_LINE_MEMBER(amu880_state::ctc_z0_w)
WRITE_LINE_MEMBER(amu880_state::ctc_z2_w) WRITE_LINE_MEMBER(amu880_state::ctc_z2_w)
{ {
/* cassette transmit/receive clock */ /* cassette clock @ 39kHz */
if (state)
{
m_cnt++;
switch (m_cnt & 7) // divide by 8 to get 4883Hz
{
case 0:
m_cassette->output(m_cassbit ? 1.0 : -1.0);
break;
case 2:
m_sio->txca_w(0);
m_sio->rxca_w(0);
break;
case 4:
m_sio->txca_w(1);
m_sio->rxca_w(1);
break;
case 6:
m_sio->rxa_w((m_cassette->input() > 0.04) ? 1 : 0);
default:
break;
}
}
} }
/* Z80-SIO Interface */ /* Z80-SIO Interface */
TIMER_DEVICE_CALLBACK_MEMBER( amu880_state::tape_tick )
{
m_z80sio->rxa_w(m_cassette->input() < 0.0);
}
WRITE_LINE_MEMBER(amu880_state::cassette_w) WRITE_LINE_MEMBER(amu880_state::cassette_w)
{ {
m_cassette->output(state ? -1.0 : +1.0); m_cassbit = state;
} }
/* Z80 Daisy Chain */ /* Z80 Daisy Chain */
@ -329,11 +363,15 @@ void amu880_state::amu880(machine_config &config)
GFXDECODE(config, "gfxdecode", m_palette, gfx_amu880); GFXDECODE(config, "gfxdecode", m_palette, gfx_amu880);
PALETTE(config, m_palette, palette_device::MONOCHROME); PALETTE(config, m_palette, palette_device::MONOCHROME);
/* sound hardware */
SPEAKER(config, "mono").front_center();
WAVE(config, "wave", m_cassette).add_route(ALL_OUTPUTS, "mono", 0.05);
/* devices */ /* devices */
z80ctc_device& ctc(Z80CTC(config, Z80CTC_TAG, XTAL(10'000'000)/4)); z80ctc_device& ctc(Z80CTC(config, Z80CTC_TAG, XTAL(10'000'000)/4));
ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
ctc.zc_callback<0>().set(FUNC(amu880_state::ctc_z0_w)); ctc.zc_callback<0>().set(FUNC(amu880_state::ctc_z0_w));
ctc.zc_callback<1>().set(m_z80sio, FUNC(z80dart_device::rxtxcb_w)); ctc.zc_callback<1>().set(m_sio, FUNC(z80dart_device::rxtxcb_w));
ctc.zc_callback<2>().set(FUNC(amu880_state::ctc_z2_w)); ctc.zc_callback<2>().set(FUNC(amu880_state::ctc_z2_w));
z80pio_device& pio1(Z80PIO(config, Z80PIO1_TAG, XTAL(10'000'000)/4)); z80pio_device& pio1(Z80PIO(config, Z80PIO1_TAG, XTAL(10'000'000)/4));
@ -342,14 +380,12 @@ void amu880_state::amu880(machine_config &config)
z80pio_device& pio2(Z80PIO(config, Z80PIO2_TAG, XTAL(10'000'000)/4)); z80pio_device& pio2(Z80PIO(config, Z80PIO2_TAG, XTAL(10'000'000)/4));
pio2.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); pio2.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
Z80SIO0(config, m_z80sio, XTAL(10'000'000)/4); // U856 Z80SIO0(config, m_sio, XTAL(10'000'000)/4); // U856
m_z80sio->out_txda_callback().set(FUNC(amu880_state::cassette_w)); m_sio->out_txda_callback().set(FUNC(amu880_state::cassette_w));
m_z80sio->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); m_sio->out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
CASSETTE(config, m_cassette); CASSETTE(config, m_cassette);
m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_MUTED); m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
TIMER(config, "tape").configure_periodic(FUNC(amu880_state::tape_tick), attotime::from_hz(44100));
/* internal ram */ /* internal ram */
RAM(config, RAM_TAG).set_default_size("64K"); RAM(config, RAM_TAG).set_default_size("64K");

View File

@ -28,7 +28,7 @@ public:
: driver_device(mconfig, type, tag) : driver_device(mconfig, type, tag)
, m_maincpu(*this, Z80_TAG) , m_maincpu(*this, Z80_TAG)
, m_cassette(*this, "cassette") , m_cassette(*this, "cassette")
, m_z80sio(*this, Z80SIO_TAG) , m_sio(*this, Z80SIO_TAG)
, m_palette(*this, "palette") , m_palette(*this, "palette")
, m_kb_rom(*this, "keyboard") , m_kb_rom(*this, "keyboard")
, m_char_rom(*this, "chargen") , m_char_rom(*this, "chargen")
@ -44,11 +44,12 @@ public:
protected: protected:
virtual void machine_start() override; virtual void machine_start() override;
virtual void machine_reset() override { m_maincpu->set_pc(0xf000); }
private: private:
required_device<z80_device> m_maincpu; required_device<z80_device> m_maincpu;
required_device<cassette_image_device> m_cassette; required_device<cassette_image_device> m_cassette;
required_device<z80dart_device> m_z80sio; required_device<z80dart_device> m_sio;
required_device<palette_device> m_palette; required_device<palette_device> m_palette;
required_memory_region m_kb_rom; required_memory_region m_kb_rom;
required_memory_region m_char_rom; required_memory_region m_char_rom;
@ -59,7 +60,6 @@ private:
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_READ8_MEMBER( keyboard_r ); DECLARE_READ8_MEMBER( keyboard_r );
TIMER_DEVICE_CALLBACK_MEMBER( tape_tick );
void scan_keyboard(); void scan_keyboard();
@ -77,6 +77,10 @@ private:
DECLARE_WRITE_LINE_MEMBER(cassette_w); DECLARE_WRITE_LINE_MEMBER(cassette_w);
void amu880_io(address_map &map); void amu880_io(address_map &map);
void amu880_mem(address_map &map); void amu880_mem(address_map &map);
// cassette variables
u8 m_cnt;
bool m_cassbit;
}; };
#endif #endif