diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 11b8e4ea7b8..90ba83740a2 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -3659,6 +3659,20 @@ if (BUSES["SBUS"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/bus/qbus/qbus.h,BUSES["QBUS"] = true +--------------------------------------------------- + +if (BUSES["QBUS"]~=null) then + files { + MAME_DIR .. "src/devices/bus/qbus/pc11.cpp", + MAME_DIR .. "src/devices/bus/qbus/pc11.h", + MAME_DIR .. "src/devices/bus/qbus/qbus.cpp", + MAME_DIR .. "src/devices/bus/qbus/qbus.h", + } +end + --------------------------------------------------- -- --@src/devices/bus/ql/exp.h,BUSES["QL"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 01212b75152..bf83b93d972 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -873,6 +873,7 @@ BUSES["PSI_KEYBOARD"] = true BUSES["PSX_CONTROLLER"] = true BUSES["PSX_PARALLEL"] = true BUSES["QL"] = true +BUSES["QBUS"] = true BUSES["RS232"] = true BUSES["S100"] = true BUSES["SAT_CTRL"] = true diff --git a/src/devices/bus/qbus/pc11.cpp b/src/devices/bus/qbus/pc11.cpp new file mode 100644 index 00000000000..fbe0a5c035e --- /dev/null +++ b/src/devices/bus/qbus/pc11.cpp @@ -0,0 +1,230 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/*************************************************************************** + + DEC PC11 paper tape reader and punch controller (punch not implemented) + +***************************************************************************/ + +#include "pc11.h" + + +//#define LOG_GENERAL (1U << 0) +#define LOG_DBG (1U << 2) + +//#define VERBOSE (LOG_GENERAL | LOG_DBG) +//#define LOG_OUTPUT_FUNC printf + +#include "logmacro.h" + +#define LOGDBG(...) LOGMASKED(LOG_DBG, __VA_ARGS__) + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(DEC_PC11, pc11_device, "pc11", "DEC PC11 controller") + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +enum +{ + REGISTER_RCSR = 0, + REGISTER_RBUF, + REGISTER_TCSR, + REGISTER_TBUF +}; + +const char* pc11_regnames[] = { + "RCSR", "RBUF", "TCSR", "TBUF" +}; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// pc11_device - constructor +//------------------------------------------------- + +pc11_device::pc11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, DEC_PC11, tag, owner, clock) + , device_image_interface(mconfig, *this) + , device_qbus_card_interface(mconfig, *this) + , m_rxvec(070) + , m_txvec(074) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pc11_device::device_start() +{ + m_bus->install_device(0177550, 0177557, read16_delegate(*this, FUNC(pc11_device::read)), + write16_delegate(*this, FUNC(pc11_device::write))); + + // resolve callbacks + + // save state + save_item(NAME(m_rcsr)); + save_item(NAME(m_rbuf)); + save_item(NAME(m_tcsr)); + save_item(NAME(m_tbuf)); + + // about 300 cps + emu_timer *timer = timer_alloc(); + timer->adjust(attotime::from_usec(333), 0, attotime::from_usec(333)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void pc11_device::device_reset() +{ + LOG("Reset, rxvec %03o txvec %03o\n", m_rxvec, m_txvec); + + m_rcsr = m_rbuf = m_tbuf = 0; + m_tcsr = CSR_DONE; + m_rxrdy = m_txrdy = CLEAR_LINE; + + m_bus->birq4_w(CLEAR_LINE); +} + +int pc11_device::z80daisy_irq_state() +{ + if (m_rxrdy == ASSERT_LINE || m_txrdy == ASSERT_LINE) + return Z80_DAISY_INT; + else + return 0; +} + +int pc11_device::z80daisy_irq_ack() +{ + int vec = -1; + + if (m_rxrdy == ASSERT_LINE) + { + m_rxrdy = CLEAR_LINE; + vec = m_rxvec; + } + else if (m_txrdy == ASSERT_LINE) + { + m_txrdy = CLEAR_LINE; + vec = m_txvec; + } + + if (vec > 0) + LOGDBG("IRQ ACK vec %03o\n", vec); + + return vec; +} + +void pc11_device::z80daisy_irq_reti() +{ +} + + +image_init_result pc11_device::call_load() +{ + /* reader unit */ + m_fd = this; + m_rcsr &= ~(CSR_ERR | CSR_BUSY); + + LOG("call_load filename %s is_open %d\n", m_fd->filename(), m_fd->is_open()); + + return image_init_result::PASS; +} + +void pc11_device::call_unload() +{ + /* reader unit */ + m_fd = nullptr; + m_rcsr |= CSR_ERR; +} + + +//------------------------------------------------- +// read - register read +//------------------------------------------------- + +READ16_MEMBER(pc11_device::read) +{ + uint16_t data = 0; + + switch (offset & 0x03) + { + case REGISTER_RCSR: + data = m_rcsr & PTRCSR_IMP; + break; + + case REGISTER_RBUF: + data = m_rbuf & 0377; + m_rcsr &= ~CSR_DONE; + clear_virq(m_bus->birq4_w, m_rcsr, CSR_IE, m_rxrdy); + break; + } + + LOGDBG("R %06o == %06o\n", 0177550 + (offset << 1), data); + + return data; +} + + +//------------------------------------------------- +// write - register write +//------------------------------------------------- + +WRITE16_MEMBER(pc11_device::write) +{ + LOGDBG("W %06o <- %06o\n", 0177550 + (offset << 1), data); + + switch (offset & 0x03) + { + case REGISTER_RCSR: + if ((data & CSR_IE) == 0) + { + clear_virq(m_bus->birq4_w, 1, 1, m_rxrdy); + } + else if ((m_rcsr & (CSR_DONE + CSR_IE)) == CSR_DONE) + { + raise_virq(m_bus->birq4_w, 1, 1, m_rxrdy); + } + if (data & CSR_GO) + { + m_rcsr = (m_rcsr & ~CSR_DONE) | CSR_BUSY; + clear_virq(m_bus->birq4_w, m_rcsr, CSR_IE, m_rxrdy); + } + m_rcsr = ((m_rcsr & ~PTRCSR_WR) | (data & PTRCSR_WR)); + break; + + case REGISTER_RBUF: + break; + } +} + +void pc11_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + uint8_t reply; + + if (!(m_rcsr & CSR_BUSY)) + return; + + LOGDBG("Timer rcsr %06o id %d param %d m_fd %p\n", m_rcsr, id, param, m_fd); + + m_rcsr = (m_rcsr | CSR_ERR) & ~CSR_BUSY; + if (m_fd && m_fd->exists() && (m_fd->fread(&reply, 1) == 1)) + { + m_rcsr = (m_rcsr | CSR_DONE) & ~CSR_ERR; + m_rbuf = reply; + } + raise_virq(m_bus->birq4_w, m_rcsr, CSR_IE, m_rxrdy); +} diff --git a/src/devices/bus/qbus/pc11.h b/src/devices/bus/qbus/pc11.h new file mode 100644 index 00000000000..a92e1802cfe --- /dev/null +++ b/src/devices/bus/qbus/pc11.h @@ -0,0 +1,92 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/*************************************************************************** + + DEC PC11 paper tape reader and punch controller (punch not implemented) + +***************************************************************************/ + +#pragma once + +#ifndef __PC11__ +#define __PC11__ + +#include "emu.h" + +#include "qbus.h" + +#include "includes/pdp11.h" +#include "softlist_dev.h" + + +#define PTRCSR_IMP (CSR_ERR + CSR_BUSY + CSR_DONE + CSR_IE) +#define PTRCSR_WR (CSR_IE) +#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) +#define PTPCSR_WR (CSR_IE) + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> pc11_device + +class pc11_device : public device_t, + public device_image_interface, + public device_qbus_card_interface +{ +public: + // construction/destruction + pc11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // image-level overrides + virtual iodevice_t image_type() const noexcept override { return IO_PUNCHTAPE; } + + virtual bool is_readable() const noexcept override { return true; } + virtual bool is_writeable() const noexcept override { return false; } + virtual bool is_creatable() const noexcept override { return false; } + virtual bool must_be_loaded() const noexcept override { return false; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual const char *image_interface() const noexcept override { return "pdp11_ptap"; } + virtual const char *file_extensions() const noexcept override { return "bin,bim,lda"; } + + virtual image_init_result call_load() override; + virtual void call_unload() override; + virtual const software_list_loader &get_software_list_loader() const override { return image_software_list_loader::instance(); } + + DECLARE_READ16_MEMBER(read); + DECLARE_WRITE16_MEMBER(write); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state() override; + virtual int z80daisy_irq_ack() override; + virtual void z80daisy_irq_reti() override; + +private: + int m_rxvec; + int m_txvec; + + device_image_interface *m_fd; + + line_state m_rxrdy; + line_state m_txrdy; + + uint16_t m_rcsr; + uint16_t m_rbuf; + uint16_t m_tcsr; + uint16_t m_tbuf; + + const char *pc11_regnames[4]; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(DEC_PC11, pc11_device) + +#endif diff --git a/src/devices/bus/qbus/qbus.cpp b/src/devices/bus/qbus/qbus.cpp new file mode 100644 index 00000000000..88a7f7a188e --- /dev/null +++ b/src/devices/bus/qbus/qbus.cpp @@ -0,0 +1,178 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + DEC Q-Bus emulation (skeleton) + +**********************************************************************/ + +#include "emu.h" + +// Peripheral boards +#include "pc11.h" + +#include "qbus.h" + + +void qbus_cards(device_slot_interface &device) +{ + device.option_add("pc11", DEC_PC11); /* Paper tape reader and punch */ +} + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(QBUS, qbus_device, "qbus", "QBUS bus") +DEFINE_DEVICE_TYPE(QBUS_SLOT, qbus_slot_device, "qbus_slot", "QBUS slot") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// device_qbus_card_interface - constructor +//------------------------------------------------- + +device_qbus_card_interface::device_qbus_card_interface(const machine_config &mconfig, device_t &device) : + device_interface(device, "qbus"), + m_bus(nullptr), + m_next(nullptr) +{ +} + + +//------------------------------------------------- +// qbus_slot_device - constructor +//------------------------------------------------- +qbus_slot_device::qbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, QBUS_SLOT, tag, owner, clock), + device_slot_interface(mconfig, *this), + m_write_birq4(*this), + m_write_birq5(*this), + m_write_birq6(*this), + m_write_birq7(*this), + m_write_bdmr(*this), + m_bus(*this, DEVICE_SELF_OWNER) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void qbus_slot_device::device_start() +{ + device_qbus_card_interface *dev = dynamic_cast(get_card_device()); + if (dev) m_bus->add_card(dev); + + m_write_birq4.resolve_safe(); + m_write_birq5.resolve_safe(); + m_write_birq6.resolve_safe(); + m_write_birq7.resolve_safe(); + m_write_bdmr.resolve_safe(); +} + + +//------------------------------------------------- +// qbus_device - constructor +//------------------------------------------------- + +qbus_device::qbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, QBUS, tag, owner, clock), + device_memory_interface(mconfig, *this), + device_z80daisy_interface(mconfig, *this), + m_program_config("QBUS A18", ENDIANNESS_BIG, 16, 16, 0, address_map_constructor()), + m_out_birq4_cb(*this), + m_out_birq5_cb(*this), + m_out_birq6_cb(*this), + m_out_birq7_cb(*this), + m_out_bdmr_cb(*this) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void qbus_device::device_start() +{ + // resolve callbacks + m_out_birq4_cb.resolve_safe(); + m_out_birq5_cb.resolve_safe(); + m_out_birq6_cb.resolve_safe(); + m_out_birq7_cb.resolve_safe(); + m_out_bdmr_cb.resolve_safe(); + + m_maincpu = owner()->subdevice(m_cputag); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void qbus_device::device_reset() +{ +} + + +//------------------------------------------------- +// add_card - add card +//------------------------------------------------- + +void qbus_device::add_card(device_qbus_card_interface *card) +{ + card->m_bus = this; + m_device_list.append(*card); +} + +void qbus_device::install_device(offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, uint32_t mask) +{ + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(start, end, rhandler, whandler, mask); +} + + +//------------------------------------------------- +// z80daisy_interface +//------------------------------------------------- + +int qbus_device::z80daisy_irq_state() +{ + int data = 0; + device_qbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + data = entry->z80daisy_irq_state(); + if (data) + return data; + entry = entry->next(); + } + + return data; +} + +int qbus_device::z80daisy_irq_ack() +{ + int vec = -1; + device_qbus_card_interface *entry = m_device_list.first(); + + while (entry) + { + vec = entry->z80daisy_irq_ack(); + if (vec > 0) + return vec; + entry = entry->next(); + } + + return vec; +} + +void qbus_device::z80daisy_irq_reti() +{ +} diff --git a/src/devices/bus/qbus/qbus.h b/src/devices/bus/qbus/qbus.h new file mode 100644 index 00000000000..d0caf2f2cbd --- /dev/null +++ b/src/devices/bus/qbus/qbus.h @@ -0,0 +1,168 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev +/********************************************************************** + + DEC Q-Bus emulation (skeleton) + +**********************************************************************/ + +#ifndef MAME_BUS_QBUS_QBUS_H +#define MAME_BUS_QBUS_QBUS_H + +#pragma once + +#include "machine/z80daisy.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class qbus_device; + +// ======================> device_qbus_card_interface + +class device_qbus_card_interface : public device_interface +{ + friend class qbus_device; + template friend class simple_list; + +public: + device_qbus_card_interface *next() const { return m_next; } + + // device_qbus_card_interface overrides + virtual void biaki_w(int state) { } + virtual void bdmgi_w(int state) { } + +protected: + // construction/destruction + device_qbus_card_interface(const machine_config &mconfig, device_t &device); + + virtual int z80daisy_irq_state() { return 0; } + virtual int z80daisy_irq_ack() { return -1; } + virtual void z80daisy_irq_reti() { } + + qbus_device *m_bus; + +private: + device_qbus_card_interface *m_next; +}; + + + +// ======================> qbus_device + +class qbus_device : public device_t, + public device_memory_interface, + public device_z80daisy_interface +{ +public: + // construction/destruction + qbus_device(const machine_config &mconfig, const char *tag, device_t *owner, const char *cputag) + : qbus_device(mconfig, tag, owner, (uint32_t)0) + { + set_cputag(cputag); + } + + qbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + ~qbus_device() { m_device_list.detach_all(); } + + // inline configuration + void set_cputag(const char *tag) { m_cputag = tag; } + + virtual space_config_vector memory_space_config() const override + { + return space_config_vector { + std::make_pair(AS_PROGRAM, &m_program_config) + }; + } + + auto birq4() { return m_out_birq4_cb.bind(); } + auto birq5() { return m_out_birq6_cb.bind(); } + auto birq6() { return m_out_birq6_cb.bind(); } + auto birq7() { return m_out_birq7_cb.bind(); } + + void add_card(device_qbus_card_interface *card); + void install_device(offs_t start, offs_t end, read16_delegate rhandler, write16_delegate whandler, uint32_t mask=0xffffffff); + + DECLARE_WRITE_LINE_MEMBER(birq4_w) { m_out_birq4_cb(state); } + DECLARE_WRITE_LINE_MEMBER(birq5_w) { m_out_birq5_cb(state); } + DECLARE_WRITE_LINE_MEMBER(birq6_w) { m_out_birq6_cb(state); } + DECLARE_WRITE_LINE_MEMBER(birq7_w) { m_out_birq7_cb(state); } + + DECLARE_WRITE_LINE_MEMBER(bdmr_w) { m_out_bdmr_cb(state); } + + const address_space_config m_program_config; + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + // device_z80daisy_interface overrides + virtual int z80daisy_irq_state() override; + virtual int z80daisy_irq_ack() override; + virtual void z80daisy_irq_reti() override; + + // internal state + cpu_device *m_maincpu; + const char *m_cputag; + +private: + devcb_write_line m_out_birq4_cb; + devcb_write_line m_out_birq5_cb; + devcb_write_line m_out_birq6_cb; + devcb_write_line m_out_birq7_cb; + devcb_write_line m_out_bdmr_cb; + + simple_list m_device_list; +}; + + +// ======================> qbus_slot_device + +class qbus_slot_device : public device_t, public device_slot_interface +{ +public: + // construction/destruction + template + qbus_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt) + : qbus_slot_device(mconfig, tag, owner, DERIVED_CLOCK(1, 1)) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + qbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // computer interface + DECLARE_WRITE_LINE_MEMBER( biaki_w ) { if (m_card) m_card->biaki_w(state); } + DECLARE_WRITE_LINE_MEMBER( bdmgi_w ) { if (m_card) m_card->bdmgi_w(state); } + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override { if (m_card) get_card_device()->reset(); } + + devcb_write_line m_write_birq4; + devcb_write_line m_write_birq5; + devcb_write_line m_write_birq6; + devcb_write_line m_write_birq7; + devcb_write_line m_write_bdmr; + + device_qbus_card_interface *m_card; + +private: + required_device m_bus; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(QBUS, qbus_device) +DECLARE_DEVICE_TYPE(QBUS_SLOT, qbus_slot_device) + +void qbus_cards(device_slot_interface &device); + +#endif // MAME_BUS_QBUS_QBUS_H diff --git a/src/mame/drivers/pdp11.cpp b/src/mame/drivers/pdp11.cpp index 6a0d3b990a1..e653e7ecef2 100644 --- a/src/mame/drivers/pdp11.cpp +++ b/src/mame/drivers/pdp11.cpp @@ -89,6 +89,7 @@ ****************************************************************************/ #include "emu.h" +#include "bus/qbus/qbus.h" #include "cpu/t11/t11.h" #include "cpu/i86/i186.h" #include "machine/terminal.h" @@ -102,6 +103,7 @@ public: : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_terminal(*this, "terminal") + , m_qbus(*this, "qbus") { } void pdp11ub2(machine_config &config); @@ -112,6 +114,7 @@ public: private: required_device m_maincpu; required_device m_terminal; + required_device m_qbus; DECLARE_READ16_MEMBER( teletype_ctrl_r ); DECLARE_WRITE16_MEMBER( teletype_ctrl_w ); void kbd_put(u8 data); @@ -378,6 +381,13 @@ void pdp11_state::pdp11(machine_config &config) m_terminal->set_keyboard_callback(FUNC(pdp11_state::kbd_put)); RX01(config, "rx01", 0); + QBUS(config, m_qbus, 0); + m_qbus->set_cputag("maincpu"); + m_qbus->birq4().set_inputline(m_maincpu, T11_IRQ0); + QBUS_SLOT(config, "qbus" ":1", qbus_cards, "pc11"); + QBUS_SLOT(config, "qbus" ":2", qbus_cards, nullptr); + QBUS_SLOT(config, "qbus" ":3", qbus_cards, nullptr); + QBUS_SLOT(config, "qbus" ":4", qbus_cards, nullptr); } void pdp11_state::pdp11ub2(machine_config &config) diff --git a/src/mame/includes/pdp11.h b/src/mame/includes/pdp11.h new file mode 100644 index 00000000000..a5170f45674 --- /dev/null +++ b/src/mame/includes/pdp11.h @@ -0,0 +1,41 @@ +// license:GPL-2.0+ +// copyright-holders:SIMH project +/***************************************************************************** + * + * includes/pdp11.h + * + ****************************************************************************/ + +#ifndef PDP11_H_ +#define PDP11_H_ + +/* + * taken from PDP11/pdp11_defs.h in SIMH + */ + +/* Device CSRs */ + +#define CSR_V_GO 0 /* go */ +#define CSR_V_IE 6 /* interrupt enable */ +#define CSR_V_DONE 7 /* done */ +#define CSR_V_BUSY 11 /* busy */ +#define CSR_V_ERR 15 /* error */ +#define CSR_GO (1u << CSR_V_GO) +#define CSR_IE (1u << CSR_V_IE) +#define CSR_DONE (1u << CSR_V_DONE) +#define CSR_BUSY (1u << CSR_V_BUSY) +#define CSR_ERR (1u << CSR_V_ERR) + + +#define clear_virq(_callback, _csr, _ie, _intrq) \ + if ((_csr) & (_ie)) { (_intrq) = CLEAR_LINE; } + +#define raise_virq(_callback, _csr, _ie, _intrq) \ + if ((_csr) & (_ie)) { (_intrq) = ASSERT_LINE; _callback (ASSERT_LINE); } + + +#define UPDATE_16BIT(_storage, _data, _mask) \ + do { *_storage = ((*_storage & ~_mask) | (_data & _mask)); } while (0) + + +#endif /* PDP11_H_ */