Add bus/adb for real ADB device emulation [O. Galibert, R. Belmont]

This commit is contained in:
arbee 2021-04-06 22:40:10 -04:00
parent ec1cbee4c4
commit e42e059b23
9 changed files with 324 additions and 18 deletions

View File

@ -190,6 +190,19 @@ if (BUSES["ADAMNET"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/bus/adb/adb.h,BUSES["ADB"] = true
---------------------------------------------------
if (BUSES["ADB"]~=null) then
files {
MAME_DIR .. "src/devices/bus/adb/adb.cpp",
MAME_DIR .. "src/devices/bus/adb/adb.h",
MAME_DIR .. "src/devices/bus/adb/adbhle.cpp",
MAME_DIR .. "src/devices/bus/adb/adbhle.h",
}
end
---------------------------------------------------
--

View File

@ -754,6 +754,7 @@ MACHINES["VRENDER0"] = true
--BUSES["ABCKB"] = true
--BUSES["ADAM"] = true
--BUSES["ADAMNET"] = true
--BUSES["ADB"] = true
--BUSES["APF"] = true
BUSES["AMIGA_KEYBOARD"] = true
--BUSES["ARCADIA"] = true

View File

@ -824,6 +824,7 @@ BUSES["ABCKB"] = true
BUSES["ACORN"] = true
BUSES["ADAM"] = true
BUSES["ADAMNET"] = true
BUSES["ADB"] = true
BUSES["APF"] = true
BUSES["APRICOT_EXPANSION"] = true
BUSES["APRICOT_KEYBOARD"] = true

View File

@ -0,0 +1,64 @@
// license:BSD-3-Clause
// copyright-holders: Olivier Galibert
// ADB - Apple Desktop Bus
//
// The serial desktop device bus from before USB was cool.
//
// Single data wire + poweron line, open collector
#include "emu.h"
#include "adb.h"
#include "adbhle.h"
DEFINE_DEVICE_TYPE(ADB_CONNECTOR, adb_connector, "adbslot", "ADB connector")
adb_connector::adb_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, ADB_CONNECTOR, tag, owner, clock),
device_single_card_slot_interface<adb_slot_card_interface>(mconfig, *this)
{
}
void adb_connector::device_start()
{
}
adb_device *adb_connector::get_device()
{
adb_slot_card_interface *const connected = get_card_device();
if (connected)
return connected->device().subdevice<adb_device>(connected->m_adb.finder_tag());
else
return nullptr;
}
adb_slot_card_interface::adb_slot_card_interface(const machine_config &mconfig, device_t &device, const char *adb_tag) :
device_interface(device, "adb"),
m_adb(*this, adb_tag)
{
}
adb_device::adb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
m_adb_cb(*this),
m_poweron_cb(*this)
{
}
void adb_device::device_start()
{
}
void adb_device::device_reset()
{
m_adb_istate = true;
m_adb_ostate = true;
}
void adb_device::default_devices(device_slot_interface &device)
{
device.option_add("hle", ADB_HLE);
}

73
src/devices/bus/adb/adb.h Normal file
View File

@ -0,0 +1,73 @@
// license:BSD-3-Clause
// copyright-holders: Olivier Galibert
// ADB - Apple Desktop Bus
//
// The serial desktop device bus from before USB was cool.
//
// Single data wire + poweron line, open collector
#ifndef MAME_BUS_ADB_ADB_H
#define MAME_BUS_ADB_ADB_H
#pragma once
class adb_device;
class adb_slot_card_interface;
class adb_connector: public device_t, public device_single_card_slot_interface<adb_slot_card_interface>
{
public:
template <typename T>
adb_connector(const machine_config &mconfig, const char *tag, device_t *owner, T &&opts, const char *dflt, bool fixed = false)
: adb_connector(mconfig, tag, owner, 0)
{
option_reset();
opts(*this);
set_default_option(dflt);
set_fixed(fixed);
}
adb_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual ~adb_connector() = default;
adb_device *get_device();
protected:
virtual void device_start() override;
};
class adb_slot_card_interface : public device_interface
{
friend class adb_connector;
public:
adb_slot_card_interface(const machine_config &mconfig, device_t &device, const char *adb_tag);
private:
required_device<adb_device> m_adb;
};
class adb_device: public device_t
{
public:
virtual void adb_w(int state) = 0;
auto adb_r() { return m_adb_cb.bind(); }
auto poweron_r() { return m_poweron_cb.bind(); }
static void default_devices(device_slot_interface &device);
protected:
adb_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;
private:
devcb_write_line m_adb_cb;
devcb_write_line m_poweron_cb;
bool m_adb_istate, m_adb_ostate;
};
DECLARE_DEVICE_TYPE(ADB_CONNECTOR, adb_connector)
#endif

View File

@ -0,0 +1,45 @@
// license:BSD-3-Clause
// copyright-holders: Olivier Galibert
// ADB - Apple Desktop Bus
//
// Generic HLE
#include "emu.h"
#include "adbhle.h"
DEFINE_DEVICE_TYPE(ADB_HLE, adb_hle_device, "adbhle", "ADB HLE")
adb_hle_device::adb_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
adb_device(mconfig, ADB_HLE, tag, owner, clock),
adb_slot_card_interface(mconfig, *this, DEVICE_SELF)
{
}
void adb_hle_device::device_start()
{
adb_device::device_start();
save_item(NAME(m_last_state));
save_item(NAME(m_last_state_time));
}
void adb_hle_device::device_reset()
{
adb_device::device_reset();
m_last_state = true;
m_last_state_time = machine().time();
}
void adb_hle_device::adb_w(int state)
{
if(m_last_state != state) {
attotime delta = machine().time() - m_last_state_time;
u32 dt = delta.as_ticks(1000000);
logerror("level %d duration %6d us\n", m_last_state, dt);
m_last_state = state;
m_last_state_time = machine().time();
}
}

View File

@ -0,0 +1,33 @@
// license:BSD-3-Clause
// copyright-holders: Olivier Galibert
// ADB - Apple Desktop Bus
//
// Generic HLE
#ifndef MAME_BUS_ADB_ADBHLE_H
#define MAME_BUS_ADB_ADBHLE_H
#pragma once
#include "adb.h"
class adb_hle_device : public adb_device, public adb_slot_card_interface
{
public:
adb_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void adb_w(int state) override;
private:
bool m_last_state;
attotime m_last_state_time;
};
DECLARE_DEVICE_TYPE(ADB_HLE, adb_hle_device)
#endif

View File

@ -97,21 +97,49 @@ const tiny_rom_entry *egret_device::device_rom_region() const
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
#if USE_BUS_ADB
void egret_device::adb_w(int id, int state)
{
m_adb_device_out[id] = state;
adb_change();
}
void egret_device::adb_poweron_w(int id, int state)
{
m_adb_device_poweron[id] = state;
}
void egret_device::adb_change()
{
bool adb = m_adb_out & m_adb_device_out[0] & m_adb_device_out[1];
logerror("adb c:%d 1:%d 2:%d -> %d (%02x %02x)\n", m_adb_out, m_adb_device_out[0], m_adb_device_out[1], adb, ddrs[0], ports[0]);
for (int i = 0; i != 2; i++)
if (m_adb_device[i])
{
m_adb_device[i]->adb_w(adb);
}
}
#endif
void egret_device::send_port(uint8_t offset, uint8_t data)
{
switch (offset)
{
case 0: // port A
/* printf("ADB:%d DFAC:%d PowerEnable:%d\n",
case 0: // port A
/* printf("ADB:%d DFAC:%d PowerEnable:%d\n",
(data & 0x80) ? 1 : 0,
(data & 0x10) ? 1 : 0,
(data & 0x02) ? 1 : 0);*/
if ((data & 0x80) != last_adb)
{
m_adb_dtime = (int)(machine().time().as_ticks(1000000) - last_adb_time);
/*
#if USE_BUS_ADB
// the line goes to a mosfet pulling the adb data line to graound, hence the inversion
m_adb_out = !(data & 0x80);
adb_change();
#else
if ((data & 0x80) != last_adb)
{
m_adb_dtime = (int)(machine().time().as_ticks(1000000) - last_adb_time);
/*
if (data & 0x80)
{
printf("EG ADB: 1->0 time %d\n", m_adb_dtime);
@ -121,14 +149,15 @@ void egret_device::send_port(uint8_t offset, uint8_t data)
printf("EG ADB: 0->1 time %d\n", m_adb_dtime);
}
*/
// allow the linechange handler to override us
adb_in = (data & 0x80) ? true : false;
// allow the linechange handler to override us
adb_in = (data & 0x80) ? true : false;
write_linechange(((data & 0x80) >> 7) ^ 1);
write_linechange(((data & 0x80) >> 7) ^ 1);
last_adb = data & 0x80;
last_adb_time = machine().time().as_ticks(1000000);
last_adb = data & 0x80;
last_adb_time = machine().time().as_ticks(1000000);
}
#endif
break;
case 1: // port B
@ -205,8 +234,12 @@ uint8_t egret_device::ports_r(offs_t offset)
switch (offset)
{
case 0: // port A
#if USE_BUS_ADB
incoming |= (m_adb_out & m_adb_device_out[0] & m_adb_device_out[1]) ? 0x40 : 0;
incoming |= (m_adb_device_poweron[0] & m_adb_device_poweron[1]) ? 0x04 : 0;
#else
incoming |= adb_in ? 0x40 : 0;
#endif
if (egret_controls_power)
{
incoming |= 0x02; // indicate soft power, indicate chassis switch on
@ -327,12 +360,15 @@ void egret_device::pram_w(offs_t offset, uint8_t data)
egret_device::egret_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, EGRET, tag, owner, clock),
device_nvram_interface(mconfig, *this),
write_reset(*this),
write_linechange(*this),
write_via_clock(*this),
write_via_data(*this),
m_maincpu(*this, EGRET_CPU_TAG)
device_nvram_interface(mconfig, *this),
write_reset(*this),
write_linechange(*this),
write_via_clock(*this),
write_via_data(*this),
m_maincpu(*this, EGRET_CPU_TAG)
#if USE_BUS_ADB
, m_adb_connector{{*this, ":adb1"}, {*this, finder_base::DUMMY_TAG}}
#endif
{
}
@ -347,6 +383,18 @@ void egret_device::device_start()
write_via_clock.resolve_safe();
write_via_data.resolve_safe();
#if USE_BUS_ADB
for (int i = 0; i < 2; i++)
{
m_adb_device[i] = m_adb_connector[i] ? m_adb_connector[i]->get_device() : nullptr;
if (m_adb_device[i])
{
m_adb_device[i]->adb_r().set([this, i](int state) { adb_w(i, state); });
m_adb_device[i]->poweron_r().set([this, i](int state) { adb_poweron_w(i, state); });
}
}
#endif
m_timer = timer_alloc(0, nullptr);
save_item(NAME(ddrs[0]));
save_item(NAME(ddrs[1]));
@ -369,6 +417,11 @@ void egret_device::device_start()
save_item(NAME(pram_loaded));
save_item(NAME(pram));
save_item(NAME(disk_pram));
#if USE_BUS_ADB
save_item(NAME(m_adb_out));
save_item(NAME(m_adb_device_out));
save_item(NAME(m_adb_device_poweron));
#endif
uint8_t *rom = device().machine().root_device().memregion(device().subtag(EGRET_CPU_TAG))->base();
@ -388,6 +441,11 @@ void egret_device::device_reset()
ddrs[0] = ddrs[1] = ddrs[2] = 0;
ports[0] = ports[1] = ports[2] = 0;
#if USE_BUS_ADB
m_adb_device_out[0] = m_adb_device_out[1] = true;
m_adb_device_poweron[0] = m_adb_device_poweron[1] = true;
#endif
m_timer->adjust(attotime::never);
egret_controls_power = false; // set to hard power control

View File

@ -5,7 +5,11 @@
#pragma once
#define USE_BUS_ADB (0)
#if USE_BUS_ADB
#include "bus/adb/adb.h"
#endif
//**************************************************************************
// MACROS / CONSTANTS
@ -59,6 +63,12 @@ public:
uint8_t pram_r(offs_t offset);
void pram_w(offs_t offset, uint8_t data);
#if USE_BUS_ADB
void adb_w(int id, int state);
void adb_poweron_w(int id, int state);
void adb_change();
#endif
// interface routines
uint8_t get_xcvr_session() { return xcvr_session; }
void set_via_full(uint8_t val) { via_full = val; }
@ -107,6 +117,14 @@ private:
uint8_t pram[0x100], disk_pram[0x100];
bool pram_loaded;
#if USE_BUS_ADB
optional_device <adb_connector> m_adb_connector[2];
adb_device *m_adb_device[2];
bool m_adb_device_out[2];
bool m_adb_device_poweron[2];
bool m_adb_out;
#endif
void send_port(uint8_t offset, uint8_t data);
};