mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
HP IPC: support for I/O slots and 82919 serial card added (#7001)
* mc68681: tx/rx clocking from timer fixed, added partial support for break signal * hp_ipc: support for I/O slots added, 82919 serial I/O card added
This commit is contained in:
parent
b31859d6c5
commit
943fc34f39
@ -4103,6 +4103,20 @@ if (BUSES["HP9845_IO"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/bus/hp_ipc_io/hp_ipc_io.h,BUSES["HP_IPC_IO"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (BUSES["HP_IPC_IO"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/bus/hp_ipc_io/hp_ipc_io.cpp",
|
||||
MAME_DIR .. "src/devices/bus/hp_ipc_io/hp_ipc_io.h",
|
||||
MAME_DIR .. "src/devices/bus/hp_ipc_io/82919.cpp",
|
||||
MAME_DIR .. "src/devices/bus/hp_ipc_io/829919.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/bus/compis/graphics.h,BUSES["COMPIS_GRAPHICS"] = true
|
||||
|
@ -860,6 +860,7 @@ BUSES["ISBX"] = true
|
||||
BUSES["JAKKS_GAMEKEY"] = true
|
||||
BUSES["HP80_IO"] = true
|
||||
BUSES["HP9845_IO"] = true
|
||||
BUSES["HP_IPC_IO"] = true
|
||||
BUSES["KC"] = true
|
||||
BUSES["LPCI"] = true
|
||||
BUSES["M5"] = true
|
||||
|
252
src/devices/bus/hp_ipc_io/82919.cpp
Normal file
252
src/devices/bus/hp_ipc_io/82919.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders: F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
82919.cpp
|
||||
|
||||
82919 module (RS232 interface)
|
||||
|
||||
Main reference for this module is:
|
||||
HP 82919-90009, feb 85, HP82919A Integral PC Serial Interface -
|
||||
Component level service manual
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "82919.h"
|
||||
#include "coreutil.h"
|
||||
|
||||
// Debugging
|
||||
#define VERBOSE 0
|
||||
#include "logmacro.h"
|
||||
|
||||
// Bit manipulation
|
||||
namespace {
|
||||
template<typename T> constexpr T BIT_MASK(unsigned n)
|
||||
{
|
||||
return (T)1U << n;
|
||||
}
|
||||
|
||||
template<typename T> void BIT_SET(T& w , unsigned n)
|
||||
{
|
||||
w |= BIT_MASK<T>(n);
|
||||
}
|
||||
}
|
||||
|
||||
hp82919_io_card_device::hp82919_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig , HP82919_IO_CARD , tag , owner , clock)
|
||||
, device_hp_ipc_io_interface(mconfig, *this)
|
||||
, m_rs232_prim(*this , "rs232_prim")
|
||||
, m_rs232_sec(*this , "rs232_sec")
|
||||
, m_uart(*this , "uart")
|
||||
, m_loopback_en(*this, "loop")
|
||||
{
|
||||
}
|
||||
|
||||
hp82919_io_card_device::~hp82919_io_card_device()
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t hp82919_io_card_device::read(offs_t addr)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
offs_t uart_addr = (addr ^ 0xc) & 0xf;
|
||||
|
||||
if (BIT(addr , 4)) {
|
||||
res = m_uart->read(uart_addr);
|
||||
} else {
|
||||
// 2 is 82919 ID code
|
||||
res = 2;
|
||||
res |= (m_int_level << 4);
|
||||
if (m_int_pending) {
|
||||
BIT_SET(res , 6);
|
||||
}
|
||||
if (m_int_en) {
|
||||
BIT_SET(res , 7);
|
||||
}
|
||||
m_uart->write(uart_addr , res);
|
||||
}
|
||||
LOG("RD %04x=%02x\n" , addr , res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void hp82919_io_card_device::write(offs_t addr , uint8_t data)
|
||||
{
|
||||
LOG("WR %04x=%02x\n" , addr , data);
|
||||
offs_t uart_addr = (addr ^ 0xc) & 0xf;
|
||||
m_uart->write(uart_addr , data);
|
||||
if (!BIT(addr , 4)) {
|
||||
m_int_level = (data >> 4) & 3;
|
||||
m_int_forced = BIT(data , 6);
|
||||
m_int_en = BIT(data , 7);
|
||||
update_irq();
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::uart_irq)
|
||||
{
|
||||
m_uart_int = state;
|
||||
update_irq();
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::uart_a_tx)
|
||||
{
|
||||
m_rs232_prim->write_txd(state);
|
||||
if (m_loopback) {
|
||||
m_uart->rx_b_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::uart_b_tx)
|
||||
{
|
||||
m_rs232_sec->write_txd(state);
|
||||
if (m_loopback) {
|
||||
m_uart->rx_a_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
void hp82919_io_card_device::uart_output(uint8_t data)
|
||||
{
|
||||
m_rs232_prim->write_dtr(BIT(data , 0));
|
||||
m_rs232_prim->write_rts(BIT(data , 1));
|
||||
// b2 is TxClock
|
||||
m_rs232_prim->write_spds(BIT(data , 3));
|
||||
m_rs232_sec->write_rts(BIT(data , 4));
|
||||
if (m_loopback) {
|
||||
m_uart->ip0_w(BIT(data , 0));
|
||||
m_uart->ip1_w(BIT(data , 1));
|
||||
m_uart->ip2_w(BIT(data , 2));
|
||||
m_uart->ip3_w(BIT(data , 3));
|
||||
m_uart->ip4_w(BIT(data , 4));
|
||||
m_uart->ip5_w(BIT(data , 4));
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_rxd)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->rx_a_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dcd)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->ip3_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_dsr)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->ip1_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_ri)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->ip2_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::prim_cts)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->ip0_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::sec_rxd)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->rx_b_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::sec_dcd)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->ip5_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp82919_io_card_device::sec_cts)
|
||||
{
|
||||
if (!m_loopback) {
|
||||
m_uart->ip4_w(state);
|
||||
}
|
||||
}
|
||||
|
||||
void hp82919_io_card_device::install_read_write_handlers(address_space& space , uint32_t base_addr)
|
||||
{
|
||||
offs_t end_addr = base_addr + 0xffffU;
|
||||
|
||||
// Supervisor mode
|
||||
space.install_readwrite_handler(base_addr, end_addr, read8sm_delegate(*this, FUNC(hp82919_io_card_device::read)), write8sm_delegate(*this, FUNC(hp82919_io_card_device::write)), 0x00ff);
|
||||
// User mode
|
||||
space.install_readwrite_handler(base_addr + USER_SPACE_OFFSET, end_addr + USER_SPACE_OFFSET, read8sm_delegate(*this, FUNC(hp82919_io_card_device::read)), write8sm_delegate(*this, FUNC(hp82919_io_card_device::write)), 0x00ff);
|
||||
}
|
||||
|
||||
void hp82919_io_card_device::device_start()
|
||||
{
|
||||
}
|
||||
|
||||
void hp82919_io_card_device::device_reset()
|
||||
{
|
||||
m_loopback = m_loopback_en->read() != 0;
|
||||
m_int_level = 0;
|
||||
m_int_forced = false;
|
||||
m_int_en = false;
|
||||
m_uart_int = false;
|
||||
m_irq = true;
|
||||
update_irq();
|
||||
}
|
||||
|
||||
void hp82919_io_card_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
RS232_PORT(config, m_rs232_prim, default_rs232_devices, nullptr);
|
||||
RS232_PORT(config, m_rs232_sec, default_rs232_devices, nullptr);
|
||||
|
||||
MC68681(config , m_uart , 3.6864_MHz_XTAL);
|
||||
m_uart->irq_cb().set(FUNC(hp82919_io_card_device::uart_irq));
|
||||
m_uart->a_tx_cb().set(FUNC(hp82919_io_card_device::uart_a_tx));
|
||||
m_uart->b_tx_cb().set(FUNC(hp82919_io_card_device::uart_b_tx));
|
||||
m_uart->outport_cb().set(FUNC(hp82919_io_card_device::uart_output));
|
||||
|
||||
m_rs232_prim->rxd_handler().set(FUNC(hp82919_io_card_device::prim_rxd));
|
||||
m_rs232_prim->dcd_handler().set(FUNC(hp82919_io_card_device::prim_dcd));
|
||||
m_rs232_prim->dsr_handler().set(FUNC(hp82919_io_card_device::prim_dsr));
|
||||
m_rs232_prim->ri_handler().set(FUNC(hp82919_io_card_device::prim_ri));
|
||||
m_rs232_prim->cts_handler().set(FUNC(hp82919_io_card_device::prim_cts));
|
||||
|
||||
m_rs232_sec->rxd_handler().set(FUNC(hp82919_io_card_device::sec_rxd));
|
||||
m_rs232_sec->dcd_handler().set(FUNC(hp82919_io_card_device::sec_dcd));
|
||||
m_rs232_sec->cts_handler().set(FUNC(hp82919_io_card_device::sec_cts));
|
||||
}
|
||||
|
||||
static INPUT_PORTS_START(hp82919_port)
|
||||
PORT_START("loop")
|
||||
PORT_CONFNAME(1 , 0 , "Test loopback")
|
||||
PORT_CONFSETTING(0 , DEF_STR(Off))
|
||||
PORT_CONFSETTING(1 , DEF_STR(On))
|
||||
INPUT_PORTS_END
|
||||
|
||||
ioport_constructor hp82919_io_card_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(hp82919_port);
|
||||
}
|
||||
|
||||
void hp82919_io_card_device::update_irq()
|
||||
{
|
||||
m_int_pending = m_int_forced || m_uart_int;
|
||||
bool irq = m_int_en && m_int_pending;
|
||||
if (m_irq != irq) {
|
||||
m_irq = irq;
|
||||
LOG("IRQ %u=%d\n" , m_int_level , irq);
|
||||
irq_w(m_int_level , irq);
|
||||
}
|
||||
}
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(HP82919_IO_CARD, hp82919_io_card_device, "hp82919", "HP82919 card")
|
73
src/devices/bus/hp_ipc_io/82919.h
Normal file
73
src/devices/bus/hp_ipc_io/82919.h
Normal file
@ -0,0 +1,73 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders: F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
82919.h
|
||||
|
||||
82919 module (RS232 interface)
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MAME_BUS_HP_IPC_IO_82919_H
|
||||
#define MAME_BUS_HP_IPC_IO_82919_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "hp_ipc_io.h"
|
||||
#include "machine/mc68681.h"
|
||||
#include "bus/rs232/rs232.h"
|
||||
|
||||
class hp82919_io_card_device : public device_t, public device_hp_ipc_io_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
hp82919_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
virtual ~hp82919_io_card_device();
|
||||
|
||||
uint8_t read(offs_t addr);
|
||||
void write(offs_t addr , uint8_t data);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(uart_irq);
|
||||
DECLARE_WRITE_LINE_MEMBER(uart_a_tx);
|
||||
DECLARE_WRITE_LINE_MEMBER(uart_b_tx);
|
||||
void uart_output(uint8_t data);
|
||||
DECLARE_WRITE_LINE_MEMBER(prim_rxd);
|
||||
DECLARE_WRITE_LINE_MEMBER(prim_dcd);
|
||||
DECLARE_WRITE_LINE_MEMBER(prim_dsr);
|
||||
DECLARE_WRITE_LINE_MEMBER(prim_ri);
|
||||
DECLARE_WRITE_LINE_MEMBER(prim_cts);
|
||||
DECLARE_WRITE_LINE_MEMBER(sec_rxd);
|
||||
DECLARE_WRITE_LINE_MEMBER(sec_dcd);
|
||||
DECLARE_WRITE_LINE_MEMBER(sec_cts);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
virtual void install_read_write_handlers(address_space& space , uint32_t base_addr) override;
|
||||
|
||||
private:
|
||||
required_device<rs232_port_device> m_rs232_prim;
|
||||
required_device<rs232_port_device> m_rs232_sec;
|
||||
required_device<mc68681_device> m_uart;
|
||||
required_ioport m_loopback_en;
|
||||
|
||||
uint8_t m_int_level;
|
||||
bool m_int_en;
|
||||
bool m_int_forced;
|
||||
bool m_int_pending;
|
||||
bool m_uart_int;
|
||||
bool m_irq;
|
||||
bool m_loopback;
|
||||
|
||||
void update_irq();
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(HP82919_IO_CARD, hp82919_io_card_device)
|
||||
|
||||
#endif // MAME_BUS_HP_IPC_IO_82919_H
|
86
src/devices/bus/hp_ipc_io/hp_ipc_io.cpp
Normal file
86
src/devices/bus/hp_ipc_io/hp_ipc_io.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders: F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
hp_ipc_io.cpp
|
||||
|
||||
I/O bus of HP IPC system
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "hp_ipc_io.h"
|
||||
|
||||
// Debugging
|
||||
#define VERBOSE 0
|
||||
#include "logmacro.h"
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(HP_IPC_IO_SLOT, hp_ipc_io_slot_device, "hp ipc io slot", "HP IPC I/O Slot")
|
||||
|
||||
// +---------------------+
|
||||
// |hp_ipc_io_slot_device|
|
||||
// +---------------------+
|
||||
hp_ipc_io_slot_device::hp_ipc_io_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, HP_IPC_IO_SLOT, tag, owner, clock),
|
||||
device_single_card_slot_interface<device_hp_ipc_io_interface>(mconfig, *this),
|
||||
m_irq_cb_func(*this),
|
||||
m_slot_idx(0)
|
||||
{
|
||||
}
|
||||
|
||||
hp_ipc_io_slot_device::~hp_ipc_io_slot_device()
|
||||
{
|
||||
}
|
||||
|
||||
void hp_ipc_io_slot_device::device_start()
|
||||
{
|
||||
m_irq_cb_func.resolve_all_safe();
|
||||
}
|
||||
|
||||
uint32_t hp_ipc_io_slot_device::get_slot_base_addr() const
|
||||
{
|
||||
return m_slot_idx ? 0x710000 : 0x700000;
|
||||
}
|
||||
|
||||
void hp_ipc_io_slot_device::install_read_write_handlers(address_space& space)
|
||||
{
|
||||
device_hp_ipc_io_interface *card = get_card_device();
|
||||
|
||||
if (card != nullptr) {
|
||||
card->install_read_write_handlers(space , get_slot_base_addr());
|
||||
}
|
||||
}
|
||||
|
||||
void hp_ipc_io_slot_device::irq_w(unsigned idx , bool state)
|
||||
{
|
||||
m_irq_cb_func[ 0 ](state && idx == 0);
|
||||
m_irq_cb_func[ 1 ](state && idx == 1);
|
||||
m_irq_cb_func[ 2 ](state && idx == 2);
|
||||
m_irq_cb_func[ 3 ](state && idx == 3);
|
||||
}
|
||||
|
||||
// +--------------------------+
|
||||
// |device_hp_ipc_io_interface|
|
||||
// +--------------------------+
|
||||
device_hp_ipc_io_interface::device_hp_ipc_io_interface(const machine_config &mconfig, device_t &device) :
|
||||
device_interface(device, "hp_ipcio")
|
||||
{
|
||||
}
|
||||
|
||||
device_hp_ipc_io_interface::~device_hp_ipc_io_interface()
|
||||
{
|
||||
}
|
||||
|
||||
void device_hp_ipc_io_interface::irq_w(unsigned idx , bool state)
|
||||
{
|
||||
hp_ipc_io_slot_device *slot = downcast<hp_ipc_io_slot_device *>(device().owner());
|
||||
slot->irq_w(idx , state);
|
||||
}
|
||||
|
||||
#include "82919.h"
|
||||
|
||||
void hp_ipc_io_slot_devices(device_slot_interface &device)
|
||||
{
|
||||
device.option_add("82919_serial" , HP82919_IO_CARD);
|
||||
}
|
82
src/devices/bus/hp_ipc_io/hp_ipc_io.h
Normal file
82
src/devices/bus/hp_ipc_io/hp_ipc_io.h
Normal file
@ -0,0 +1,82 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders: F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
hp_ipc_io.h
|
||||
|
||||
I/O bus of HP IPC system
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef MAME_BUS_HP_IPC_IO_HP_IPC_IO_H
|
||||
#define MAME_BUS_HP_IPC_IO_HP_IPC_IO_H
|
||||
|
||||
#pragma once
|
||||
|
||||
void hp_ipc_io_slot_devices(device_slot_interface &device);
|
||||
|
||||
class device_hp_ipc_io_interface;
|
||||
|
||||
class hp_ipc_io_slot_device : public device_t,
|
||||
public device_single_card_slot_interface<device_hp_ipc_io_interface>
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
hp_ipc_io_slot_device(machine_config const &mconfig, char const *tag, device_t *owner)
|
||||
: hp_ipc_io_slot_device(mconfig, tag, owner, (uint32_t)0)
|
||||
{
|
||||
option_reset();
|
||||
hp_ipc_io_slot_devices(*this);
|
||||
set_default_option(nullptr);
|
||||
set_fixed(false);
|
||||
}
|
||||
|
||||
hp_ipc_io_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
virtual ~hp_ipc_io_slot_device();
|
||||
|
||||
// Set A/B slot
|
||||
void set_slot_idx(unsigned idx) { m_slot_idx = idx; }
|
||||
|
||||
// Callback setups
|
||||
auto irq3_cb() { return m_irq_cb_func[ 0 ].bind(); }
|
||||
auto irq4_cb() { return m_irq_cb_func[ 1 ].bind(); }
|
||||
auto irq5_cb() { return m_irq_cb_func[ 2 ].bind(); }
|
||||
auto irq6_cb() { return m_irq_cb_func[ 3 ].bind(); }
|
||||
|
||||
uint32_t get_slot_base_addr() const;
|
||||
|
||||
void install_read_write_handlers(address_space& space);
|
||||
|
||||
void irq_w(unsigned idx , bool state);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
|
||||
private:
|
||||
devcb_write_line::array<4> m_irq_cb_func;
|
||||
// 0: slot A
|
||||
// 1: slot B
|
||||
unsigned m_slot_idx;
|
||||
};
|
||||
|
||||
class device_hp_ipc_io_interface : public device_interface
|
||||
{
|
||||
public:
|
||||
virtual ~device_hp_ipc_io_interface();
|
||||
|
||||
virtual void install_read_write_handlers(address_space& space , uint32_t base_addr) = 0;
|
||||
|
||||
static constexpr offs_t USER_SPACE_OFFSET = 0x1800000;
|
||||
|
||||
protected:
|
||||
device_hp_ipc_io_interface(const machine_config &mconfig, device_t &device);
|
||||
|
||||
// card device handling
|
||||
void irq_w(unsigned idx , bool state);
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(HP_IPC_IO_SLOT, hp_ipc_io_slot_device)
|
||||
|
||||
#endif // MAME_BUS_HP_IPC_IO_HP_IPC_IO_H
|
@ -439,28 +439,25 @@ TIMER_CALLBACK_MEMBER(duart_base_device::duart_timer_callback)
|
||||
}
|
||||
|
||||
// timer driving any serial channels?
|
||||
if (BIT(ACR, 7) == 1)
|
||||
uint8_t csr = m_chanA->get_chan_CSR();
|
||||
|
||||
if ((csr & 0x0f) == 0x0d) // tx is timer driven
|
||||
{
|
||||
uint8_t csr = m_chanA->get_chan_CSR();
|
||||
m_chanA->tx_16x_clock_w(half_period);
|
||||
}
|
||||
if ((csr & 0xf0) == 0xd0) // rx is timer driven
|
||||
{
|
||||
m_chanA->rx_16x_clock_w(half_period);
|
||||
}
|
||||
|
||||
if ((csr & 0xf0) == 0xd0) // tx is timer driven
|
||||
{
|
||||
m_chanA->tx_clock_w(half_period);
|
||||
}
|
||||
if ((csr & 0x0f) == 0x0d) // rx is timer driven
|
||||
{
|
||||
m_chanA->rx_clock_w(half_period);
|
||||
}
|
||||
|
||||
csr = m_chanB->get_chan_CSR();
|
||||
if ((csr & 0xf0) == 0xd0) // tx is timer driven
|
||||
{
|
||||
m_chanB->tx_clock_w(half_period);
|
||||
}
|
||||
if ((csr & 0x0f) == 0x0d) // rx is timer driven
|
||||
{
|
||||
m_chanB->rx_clock_w(half_period);
|
||||
}
|
||||
csr = m_chanB->get_chan_CSR();
|
||||
if ((csr & 0x0f) == 0x0d) // tx is timer driven
|
||||
{
|
||||
m_chanB->tx_16x_clock_w(half_period);
|
||||
}
|
||||
if ((csr & 0xf0) == 0xd0) // rx is timer driven
|
||||
{
|
||||
m_chanB->rx_16x_clock_w(half_period);
|
||||
}
|
||||
|
||||
if (!half_period)
|
||||
@ -1148,8 +1145,9 @@ duart_channel::duart_channel(const machine_config &mconfig, const char *tag, dev
|
||||
, rx_enabled(0)
|
||||
, rx_fifo_num(0)
|
||||
, tx_enabled(0)
|
||||
, m_tx_break(false)
|
||||
{
|
||||
std::fill_n(&rx_fifo[0], MC68681_RX_FIFO_SIZE, 0);
|
||||
std::fill_n(&rx_fifo[0], MC68681_RX_FIFO_SIZE + 1, 0);
|
||||
}
|
||||
|
||||
void duart_channel::device_start()
|
||||
@ -1173,6 +1171,7 @@ void duart_channel::device_start()
|
||||
save_item(NAME(tx_enabled));
|
||||
save_item(NAME(tx_data));
|
||||
save_item(NAME(tx_ready));
|
||||
save_item(NAME(m_tx_break));
|
||||
}
|
||||
|
||||
void duart_channel::device_reset()
|
||||
@ -1186,6 +1185,7 @@ void duart_channel::device_reset()
|
||||
|
||||
tx_baud_rate = rx_baud_rate = 0;
|
||||
CSR = 0;
|
||||
m_tx_break = false;
|
||||
}
|
||||
|
||||
// serial device virtual overrides
|
||||
@ -1208,18 +1208,28 @@ void duart_channel::rcv_complete()
|
||||
|
||||
void duart_channel::rx_fifo_push(uint8_t data, uint8_t errors)
|
||||
{
|
||||
if (rx_fifo_num >= MC68681_RX_FIFO_SIZE)
|
||||
if (rx_fifo_num == (MC68681_RX_FIFO_SIZE + 1))
|
||||
{
|
||||
logerror("68681: FIFO overflow\n");
|
||||
SR |= STATUS_OVERRUN_ERROR;
|
||||
return;
|
||||
// In case of overrun the FIFO tail entry is overwritten
|
||||
// Back rx_fifo_write_ptr up by one position
|
||||
if (rx_fifo_write_ptr)
|
||||
rx_fifo_write_ptr--;
|
||||
else
|
||||
rx_fifo_write_ptr = MC68681_RX_FIFO_SIZE;
|
||||
}
|
||||
|
||||
rx_fifo[rx_fifo_write_ptr++] = data | (errors << 8);
|
||||
if (rx_fifo_write_ptr == MC68681_RX_FIFO_SIZE)
|
||||
if (rx_fifo_write_ptr > MC68681_RX_FIFO_SIZE)
|
||||
rx_fifo_write_ptr = 0;
|
||||
|
||||
if (rx_fifo_num++ == 0)
|
||||
if (rx_fifo_num <= MC68681_RX_FIFO_SIZE)
|
||||
{
|
||||
rx_fifo_num++;
|
||||
}
|
||||
|
||||
if (rx_fifo_num == 1)
|
||||
{
|
||||
SR |= STATUS_RECEIVER_READY;
|
||||
if (!(MR1 & MODE_BLOCK_ERROR))
|
||||
@ -1238,9 +1248,9 @@ void duart_channel::tra_complete()
|
||||
SR |= STATUS_TRANSMITTER_READY;
|
||||
|
||||
if (m_ch == 0)
|
||||
m_uart->clear_ISR_bits(INT_TXRDYA);
|
||||
m_uart->set_ISR_bits(INT_TXRDYA);
|
||||
else
|
||||
m_uart->clear_ISR_bits(INT_TXRDYB);
|
||||
m_uart->set_ISR_bits(INT_TXRDYB);
|
||||
|
||||
// if local loopback is on, write the transmitted data as if a byte had been received
|
||||
if ((MR2 & 0xc0) == 0x80)
|
||||
@ -1363,13 +1373,17 @@ uint8_t duart_channel::read_rx_fifo()
|
||||
}
|
||||
|
||||
rv = rx_fifo[rx_fifo_read_ptr++];
|
||||
if (rx_fifo_read_ptr == MC68681_RX_FIFO_SIZE)
|
||||
if (rx_fifo_read_ptr > MC68681_RX_FIFO_SIZE)
|
||||
{
|
||||
rx_fifo_read_ptr = 0;
|
||||
}
|
||||
|
||||
rx_fifo_num--;
|
||||
SR &= ~STATUS_FIFO_FULL;
|
||||
if (rx_fifo_num == (MC68681_RX_FIFO_SIZE - 1))
|
||||
{
|
||||
SR &= ~STATUS_FIFO_FULL;
|
||||
}
|
||||
|
||||
if (!(MR1 & MODE_BLOCK_ERROR))
|
||||
SR &= ~(STATUS_RECEIVED_BREAK | STATUS_FRAMING_ERROR | STATUS_PARITY_ERROR);
|
||||
if (rx_fifo_num == 0)
|
||||
@ -1549,7 +1563,36 @@ void duart_channel::write_CR(uint8_t data)
|
||||
else
|
||||
m_uart->clear_ISR_bits(INT_DELTA_BREAK_B);
|
||||
break;
|
||||
/* TODO: case 6 and case 7 are start break and stop break respectively, which start or stop holding the TxDA or TxDB line low (space) after whatever data is in the buffer finishes transmitting (following the stop bit?), or after two bit-times if no data is being transmitted */
|
||||
case 6: /* Start Tx break */
|
||||
if (!m_tx_break)
|
||||
{
|
||||
m_tx_break = true;
|
||||
if ((MR2 & 0xc0) == 0x80)
|
||||
{
|
||||
// Local loopback mode: set delta break in ISR, simulate break rx
|
||||
if (m_ch == 0)
|
||||
m_uart->set_ISR_bits(INT_DELTA_BREAK_A);
|
||||
else
|
||||
m_uart->set_ISR_bits(INT_DELTA_BREAK_B);
|
||||
rx_fifo_push(0 , STATUS_RECEIVED_BREAK);
|
||||
}
|
||||
// TODO: Actually send break signal
|
||||
}
|
||||
break;
|
||||
case 7: /* Stop tx break */
|
||||
if (m_tx_break)
|
||||
{
|
||||
m_tx_break = false;
|
||||
if ((MR2 & 0xc0) == 0x80)
|
||||
{
|
||||
// Local loopback mode: set delta break in ISR
|
||||
if (m_ch == 0)
|
||||
m_uart->set_ISR_bits(INT_DELTA_BREAK_A);
|
||||
else
|
||||
m_uart->set_ISR_bits(INT_DELTA_BREAK_B);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG("68681: Unhandled command (%x) in CR%d\n", (data >> 4) & 0x07, m_ch);
|
||||
break;
|
||||
@ -1623,3 +1666,43 @@ uint8_t duart_channel::get_chan_CSR()
|
||||
{
|
||||
return CSR;
|
||||
}
|
||||
|
||||
void duart_channel::tx_16x_clock_w(bool state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
m_tx_prescaler--;
|
||||
if (m_tx_prescaler == 8)
|
||||
{
|
||||
tx_clock_w(true);
|
||||
}
|
||||
else if (m_tx_prescaler == 0)
|
||||
{
|
||||
m_tx_prescaler = 16;
|
||||
tx_clock_w(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void duart_channel::rx_16x_clock_w(bool state)
|
||||
{
|
||||
if (!is_receive_register_synchronized())
|
||||
{
|
||||
// Skip over the start bit once synchonization is achieved
|
||||
m_rx_prescaler = 32;
|
||||
rx_clock_w(true);
|
||||
}
|
||||
else if (state)
|
||||
{
|
||||
m_rx_prescaler--;
|
||||
if (m_rx_prescaler == 8)
|
||||
{
|
||||
rx_clock_w(false);
|
||||
}
|
||||
else if (m_rx_prescaler == 0)
|
||||
{
|
||||
m_rx_prescaler = 16;
|
||||
rx_clock_w(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ public:
|
||||
void write_MR1(uint8_t data){ MR1 = data; }
|
||||
void write_MR2(uint8_t data){ MR2 = data; }
|
||||
|
||||
void tx_16x_clock_w(bool state);
|
||||
void rx_16x_clock_w(bool state);
|
||||
|
||||
private:
|
||||
/* Registers */
|
||||
uint8_t CR; /* Command register */
|
||||
@ -58,7 +61,7 @@ private:
|
||||
|
||||
/* Receiver */
|
||||
uint8_t rx_enabled;
|
||||
uint16_t rx_fifo[MC68681_RX_FIFO_SIZE];
|
||||
uint16_t rx_fifo[MC68681_RX_FIFO_SIZE + 1];
|
||||
int rx_fifo_read_ptr;
|
||||
int rx_fifo_write_ptr;
|
||||
int rx_fifo_num;
|
||||
@ -69,6 +72,10 @@ private:
|
||||
uint8_t tx_enabled;
|
||||
uint8_t tx_data;
|
||||
uint8_t tx_ready;
|
||||
bool m_tx_break;
|
||||
|
||||
/* Rx/Tx clocking */
|
||||
uint8_t m_rx_prescaler , m_tx_prescaler;
|
||||
|
||||
duart_base_device *m_uart;
|
||||
|
||||
|
@ -373,6 +373,8 @@ Software to look for
|
||||
#include "speaker.h"
|
||||
#include "sound/dac.h"
|
||||
#include "sound/volt_reg.h"
|
||||
#include "machine/input_merger.h"
|
||||
#include "bus/hp_ipc_io/hp_ipc_io.h"
|
||||
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
@ -391,6 +393,12 @@ public:
|
||||
, m_screen(*this, "screen")
|
||||
, m_spkr(*this , "spkr")
|
||||
, m_dac(*this , "dac")
|
||||
, m_irq3_merger(*this , "merge_irq3")
|
||||
, m_irq4_merger(*this , "merge_irq4")
|
||||
, m_irq5_merger(*this , "merge_irq5")
|
||||
, m_irq6_merger(*this , "merge_irq6")
|
||||
, m_io_slot_a(*this , "slot_a")
|
||||
, m_io_slot_b(*this , "slot_b")
|
||||
{ }
|
||||
|
||||
void hp_ipc_base(machine_config &config);
|
||||
@ -439,6 +447,12 @@ private:
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<cop452_device> m_spkr;
|
||||
required_device<dac_1bit_device> m_dac;
|
||||
required_device<input_merger_any_high_device> m_irq3_merger;
|
||||
required_device<input_merger_any_high_device> m_irq4_merger;
|
||||
required_device<input_merger_any_high_device> m_irq5_merger;
|
||||
required_device<input_merger_any_high_device> m_irq6_merger;
|
||||
required_device<hp_ipc_io_slot_device> m_io_slot_a;
|
||||
required_device<hp_ipc_io_slot_device> m_io_slot_b;
|
||||
|
||||
uint32_t m_mmu[4], m_lowest_ram_addr;
|
||||
uint16_t *m_internal_ram;
|
||||
@ -688,22 +702,22 @@ WRITE_LINE_MEMBER(hp_ipc_state::irq_2)
|
||||
|
||||
WRITE_LINE_MEMBER(hp_ipc_state::irq_3)
|
||||
{
|
||||
m_maincpu->set_input_line(M68K_IRQ_3, state);
|
||||
m_irq3_merger->in_w<0>(state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp_ipc_state::irq_4)
|
||||
{
|
||||
m_maincpu->set_input_line(M68K_IRQ_4, state);
|
||||
m_irq4_merger->in_w<0>(state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp_ipc_state::irq_5)
|
||||
{
|
||||
m_maincpu->set_input_line(M68K_IRQ_5, state);
|
||||
m_irq5_merger->in_w<0>(state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp_ipc_state::irq_6)
|
||||
{
|
||||
m_maincpu->set_input_line(M68K_IRQ_6, state);
|
||||
m_irq6_merger->in_w<0>(state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(hp_ipc_state::irq_7)
|
||||
@ -720,6 +734,9 @@ void hp_ipc_state::machine_start()
|
||||
|
||||
m_lowest_ram_addr = 0x3c0000 - (m_ram->size() >> 1);
|
||||
m_internal_ram = (uint16_t *)m_ram->pointer();
|
||||
|
||||
m_io_slot_a->install_read_write_handlers(m_bankdev->space());
|
||||
m_io_slot_b->install_read_write_handlers(m_bankdev->space());
|
||||
}
|
||||
|
||||
void hp_ipc_state::machine_reset()
|
||||
@ -809,6 +826,24 @@ void hp_ipc_state::hp_ipc_base(machine_config &config)
|
||||
vref.add_route(0, "dac", 1.0, DAC_VREF_POS_INPUT);
|
||||
m_spkr->oa_w().set(m_dac , FUNC(dac_1bit_device::write));
|
||||
|
||||
// IO slots
|
||||
HP_IPC_IO_SLOT(config , m_io_slot_a).set_slot_idx(0);
|
||||
HP_IPC_IO_SLOT(config , m_io_slot_b).set_slot_idx(1);
|
||||
|
||||
// IRQ3/4/5/6 mergers
|
||||
INPUT_MERGER_ANY_HIGH(config , m_irq3_merger).output_handler().set_inputline(m_maincpu , M68K_IRQ_3);
|
||||
INPUT_MERGER_ANY_HIGH(config , m_irq4_merger).output_handler().set_inputline(m_maincpu , M68K_IRQ_4);
|
||||
INPUT_MERGER_ANY_HIGH(config , m_irq5_merger).output_handler().set_inputline(m_maincpu , M68K_IRQ_5);
|
||||
INPUT_MERGER_ANY_HIGH(config , m_irq6_merger).output_handler().set_inputline(m_maincpu , M68K_IRQ_6);
|
||||
m_io_slot_a->irq3_cb().set(m_irq3_merger , FUNC(input_merger_any_high_device::in_w<1>));
|
||||
m_io_slot_a->irq4_cb().set(m_irq4_merger , FUNC(input_merger_any_high_device::in_w<1>));
|
||||
m_io_slot_a->irq5_cb().set(m_irq5_merger , FUNC(input_merger_any_high_device::in_w<1>));
|
||||
m_io_slot_a->irq6_cb().set(m_irq6_merger , FUNC(input_merger_any_high_device::in_w<1>));
|
||||
m_io_slot_b->irq3_cb().set(m_irq3_merger , FUNC(input_merger_any_high_device::in_w<2>));
|
||||
m_io_slot_b->irq4_cb().set(m_irq4_merger , FUNC(input_merger_any_high_device::in_w<2>));
|
||||
m_io_slot_b->irq5_cb().set(m_irq5_merger , FUNC(input_merger_any_high_device::in_w<2>));
|
||||
m_io_slot_b->irq6_cb().set(m_irq6_merger , FUNC(input_merger_any_high_device::in_w<2>));
|
||||
|
||||
RAM(config, RAM_TAG).set_default_size("512K").set_extra_options("768K,1M,1576K,2M,3M,4M,5M,6M,7M,7680K");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user