Merge pull request #2749 from fulivi/hp80_dev04

HP85: support for I/O slots & HP-IB interface module
This commit is contained in:
R. Belmont 2017-10-25 15:39:55 -04:00 committed by GitHub
commit fb20279b92
13 changed files with 1208 additions and 6 deletions

View File

@ -67,4 +67,17 @@
</dataarea>
</part>
</software>
<software name="mass">
<description>Mass storage ROM</description>
<year>1979</year>
<publisher>Hewlett-Packard</publisher>
<info name="serial" value="00085-15001"/>
<part name="rom" interface="hp80_rom">
<feature name="sc" value="0xD0"/>
<dataarea name="rom" size="0x2000">
<rom name="rom320.bin" size="0x2000" crc="9c03582c" sha1="1cc9a5013739821cd1d7e2a52e8abbd29045e850" offset="0"/>
</dataarea>
</part>
</software>
</softwarelist>

View File

@ -3162,6 +3162,18 @@ if (BUSES["HP80_OPTROM"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/bus/hp80_io/hp80_io.h,BUSES["HP80_IO"] = true
---------------------------------------------------
if (BUSES["HP80_IO"]~=null) then
files {
MAME_DIR .. "src/devices/bus/hp80_io/hp80_io.cpp",
MAME_DIR .. "src/devices/bus/hp80_io/82937.cpp",
}
end
---------------------------------------------------
--
--@src/devices/bus/hp9845_io/hp9845_io.h,BUSES["HP9845_IO"] = true

View File

@ -1036,6 +1036,18 @@ if (MACHINES["1MA6"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/1mb5.h,MACHINES["1MB5"] = true
---------------------------------------------------
if (MACHINES["1MB5"]~=null) then
files {
MAME_DIR .. "src/devices/machine/1mb5.cpp",
MAME_DIR .. "src/devices/machine/1mb5.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/i2cmem.h,MACHINES["I2CMEM"] = true

View File

@ -418,6 +418,7 @@ MACHINES["HD63450"] = true
MACHINES["HD64610"] = true
MACHINES["HP_TACO"] = true
MACHINES["1MA6"] = true
MACHINES["1MB5"] = true
MACHINES["I2CMEM"] = true
MACHINES["I7220"] = true
MACHINES["I80130"] = true
@ -684,6 +685,7 @@ BUSES["ISA"] = true
BUSES["ISBX"] = true
BUSES["HP_OPTROM"] = true
BUSES["HP80_OPTROM"] = true
BUSES["HP80_IO"] = true
BUSES["HP9845_IO"] = true
BUSES["KC"] = true
BUSES["LPCI"] = true

View File

@ -0,0 +1,354 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
82937.cpp
82937 module (HPIB interface)
TODO: Implement Parallel Poll response
Thanks to Tim Nye & Everett Kaser for dumping the 8049 ROM
Main reference for this module is:
HP 82937-90007, oct 80, HP82937A HP-IB Installation and theory
of operation manual
*********************************************************************/
#include "emu.h"
#include "82937.h"
#include "coreutil.h"
// Debugging
#define VERBOSE 0
#include "logmacro.h"
// Bit manipulation
namespace {
static constexpr unsigned BIT_MASK(unsigned n)
{
return 1U << n;
}
template<typename T> void BIT_SET(T& w , unsigned n)
{
w |= (T)BIT_MASK(n);
}
}
// Bits in U3 (m_latch)
static constexpr unsigned LATCH_CA_BIT = 5; // Controller Active
static constexpr unsigned LATCH_TA_BIT = 4; // Talker Active
static constexpr unsigned LATCH_EN_IFC_INT_BIT = 3; // Enable IFC interrupt
static constexpr unsigned LATCH_EN_REN_INT_BIT = 2; // Enable REN interrupt
static constexpr unsigned LATCH_EN_ATN_INT_BIT = 1; // Enable ATN interrupt
static constexpr unsigned LATCH_EN_NDAC_BIT = 0; // Enable NDAC
// Bits on P1 port of 8049
static constexpr unsigned P1_IFC_BIT = 7;
static constexpr unsigned P1_REN_BIT = 6;
static constexpr unsigned P1_SRQ_BIT = 5;
static constexpr unsigned P1_ATN_BIT = 4;
static constexpr unsigned P1_EOI_BIT = 3;
static constexpr unsigned P1_DAV_BIT = 2;
static constexpr unsigned P1_NDAC_BIT = 1;
static constexpr unsigned P1_NRFD_BIT = 0;
hp82937_io_card_device::hp82937_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: hp80_io_card_device(mconfig , HP82937_IO_CARD , tag , owner , clock),
m_cpu(*this , "cpu"),
m_translator(*this , "xlator"),
m_sw1(*this , "sw1"),
m_ieee488(*this , IEEE488_TAG)
{
}
hp82937_io_card_device::~hp82937_io_card_device()
{
}
void hp82937_io_card_device::install_read_write_handlers(address_space& space , uint16_t base_addr)
{
space.install_readwrite_handler(base_addr , base_addr + 1 , READ8_DEVICE_DELEGATE(m_translator , hp_1mb5_device , cpu_r) , WRITE8_DEVICE_DELEGATE(m_translator , hp_1mb5_device , cpu_w));
}
void hp82937_io_card_device::inten()
{
m_translator->inten();
}
void hp82937_io_card_device::clear_service()
{
m_translator->clear_service();
}
WRITE_LINE_MEMBER(hp82937_io_card_device::reset_w)
{
m_cpu->set_input_line(INPUT_LINE_RESET , state);
if (state) {
// When reset is asserted, clear state
device_reset();
}
}
READ_LINE_MEMBER(hp82937_io_card_device::t0_r)
{
return m_iatn;
}
READ8_MEMBER(hp82937_io_card_device::p1_r)
{
uint8_t res = 0;
if (BIT(m_sw1->read() , 5)) {
// System controller
BIT_SET(res , P1_IFC_BIT);
BIT_SET(res , P1_REN_BIT);
} else {
// Not system controller
if (m_ieee488->ifc_r()) {
BIT_SET(res , P1_IFC_BIT);
}
if (m_ieee488->ren_r()) {
BIT_SET(res , P1_REN_BIT);
}
}
if (!BIT(m_latch , LATCH_CA_BIT) || m_ieee488->srq_r()) {
BIT_SET(res , P1_SRQ_BIT);
}
if (m_iatn) {
BIT_SET(res , P1_ATN_BIT);
}
bool ndac = !BIT(m_latch , LATCH_EN_NDAC_BIT) || m_iatn;
if (m_talker_out) {
BIT_SET(res , P1_EOI_BIT);
BIT_SET(res , P1_DAV_BIT);
if (ndac && m_ieee488->ndac_r()) {
BIT_SET(res , P1_NDAC_BIT);
}
if (m_ieee488->nrfd_r()) {
BIT_SET(res , P1_NRFD_BIT);
}
} else {
if (m_ieee488->eoi_r()) {
BIT_SET(res , P1_EOI_BIT);
}
if (m_ieee488->dav_r()) {
BIT_SET(res , P1_DAV_BIT);
}
if (ndac) {
BIT_SET(res , P1_NDAC_BIT);
}
BIT_SET(res , P1_NRFD_BIT);
}
return res;
}
WRITE8_MEMBER(hp82937_io_card_device::p1_w)
{
update_signals();
update_data_out();
}
READ8_MEMBER(hp82937_io_card_device::dio_r)
{
if (m_dio_out) {
return 0xff;
} else {
return m_ieee488->dio_r();
}
}
WRITE8_MEMBER(hp82937_io_card_device::dio_w)
{
update_data_out();
}
READ8_MEMBER(hp82937_io_card_device::switch_r)
{
return m_sw1->read() | 0xc0;
}
WRITE8_MEMBER(hp82937_io_card_device::latch_w)
{
LOG("latch=%02x\n" , data);
m_latch = data;
update_signals();
update_data_out();
}
WRITE_LINE_MEMBER(hp82937_io_card_device::ieee488_ctrl_w)
{
update_signals();
update_data_out();
}
static INPUT_PORTS_START(hp82937_port)
MCFG_HP80_IO_SC(7)
PORT_START("sw1")
PORT_DIPNAME(0x1f , 0x15 , "HPIB address")
PORT_DIPLOCATION("S1:7,6,5,4,3")
PORT_DIPSETTING(0x00 , "0")
PORT_DIPSETTING(0x01 , "1")
PORT_DIPSETTING(0x02 , "2")
PORT_DIPSETTING(0x03 , "3")
PORT_DIPSETTING(0x04 , "4")
PORT_DIPSETTING(0x05 , "5")
PORT_DIPSETTING(0x06 , "6")
PORT_DIPSETTING(0x07 , "7")
PORT_DIPSETTING(0x08 , "8")
PORT_DIPSETTING(0x09 , "9")
PORT_DIPSETTING(0x0a , "10")
PORT_DIPSETTING(0x0b , "11")
PORT_DIPSETTING(0x0c , "12")
PORT_DIPSETTING(0x0d , "13")
PORT_DIPSETTING(0x0e , "14")
PORT_DIPSETTING(0x0f , "15")
PORT_DIPSETTING(0x10 , "16")
PORT_DIPSETTING(0x11 , "17")
PORT_DIPSETTING(0x12 , "18")
PORT_DIPSETTING(0x13 , "19")
PORT_DIPSETTING(0x14 , "20")
PORT_DIPSETTING(0x15 , "21")
PORT_DIPSETTING(0x16 , "22")
PORT_DIPSETTING(0x17 , "23")
PORT_DIPSETTING(0x18 , "24")
PORT_DIPSETTING(0x19 , "25")
PORT_DIPSETTING(0x1a , "26")
PORT_DIPSETTING(0x1b , "27")
PORT_DIPSETTING(0x1c , "28")
PORT_DIPSETTING(0x1d , "29")
PORT_DIPSETTING(0x1e , "30")
PORT_DIPSETTING(0x1f , "31")
PORT_DIPNAME(0x20 , 0x20 , "Sys. controller")
PORT_DIPLOCATION("S1:2")
PORT_DIPSETTING(0x00 , DEF_STR(Off))
PORT_DIPSETTING(0x20 , DEF_STR(On))
INPUT_PORTS_END
ioport_constructor hp82937_io_card_device::device_input_ports() const
{
return INPUT_PORTS_NAME(hp82937_port);
}
void hp82937_io_card_device::device_start()
{
save_item(NAME(m_dio_out));
save_item(NAME(m_talker_out));
save_item(NAME(m_iatn));
save_item(NAME(m_latch));
}
void hp82937_io_card_device::device_reset()
{
hp80_io_card_device::device_reset();
m_latch = 0;
m_updating = false;
update_signals();
update_data_out();
}
void hp82937_io_card_device::update_data_out()
{
m_ieee488->dio_w(m_dio_out ? m_cpu->p2_r(machine().dummy_space() , 0) : 0xff);
}
void hp82937_io_card_device::update_signals()
{
// Avoid recursive re-enter when writing to IEEE488 signals
if (m_updating) {
return;
}
m_updating = true;
bool ctrl_active = BIT(m_latch , LATCH_CA_BIT);
uint8_t p1 = m_cpu->p1_r(machine().dummy_space() , 0);
m_iatn = BIT(p1 , P1_ATN_BIT);
if (ctrl_active) {
m_ieee488->atn_w(m_iatn);
m_ieee488->srq_w(1);
} else {
m_ieee488->atn_w(1);
m_iatn = m_iatn && m_ieee488->atn_r();
m_ieee488->srq_w(BIT(p1 , P1_SRQ_BIT));
}
m_talker_out = (ctrl_active && !m_iatn) || (BIT(m_latch , LATCH_TA_BIT) && m_iatn);
if (m_talker_out) {
m_ieee488->nrfd_w(1);
m_ieee488->dav_w(BIT(p1 , P1_DAV_BIT));
m_ieee488->eoi_w(BIT(p1 , P1_EOI_BIT));
m_ieee488->ndac_w(1);
} else {
m_ieee488->nrfd_w(BIT(p1 , P1_NRFD_BIT));
m_ieee488->dav_w(1);
m_ieee488->eoi_w(1);
bool ndac = BIT(p1 , P1_NDAC_BIT);
if (BIT(m_latch , LATCH_EN_NDAC_BIT) && !m_iatn) {
ndac = false;
}
m_ieee488->ndac_w(ndac);
}
bool iren = BIT(p1 , P1_REN_BIT);
if (BIT(m_sw1->read() , 5)) {
// System controller
m_ieee488->ren_w(iren);
m_ieee488->ifc_w(BIT(p1 , P1_IFC_BIT));
} else {
// Not system controller
m_ieee488->ren_w(1);
iren = iren && m_ieee488->ren_r();
m_ieee488->ifc_w(1);
}
bool not_u8_1 = m_iatn || m_ieee488->eoi_r();
m_dio_out = not_u8_1 && m_talker_out;
bool irq = (BIT(m_latch , LATCH_EN_IFC_INT_BIT) && !m_ieee488->ifc_r()) ||
(BIT(m_latch , LATCH_EN_REN_INT_BIT) && iren) ||
(BIT(m_latch , LATCH_EN_ATN_INT_BIT) && !m_iatn);
m_cpu->set_input_line(MCS48_INPUT_IRQ , irq);
m_updating = false;
}
ROM_START(hp82937)
ROM_REGION(0x800 , "cpu" , 0)
ROM_LOAD("1820-2437.bin" , 0 , 0x800 , CRC(687d1559) SHA1(44dfc8c3f431cd37a270b094f1db751214009214))
ROM_END
static ADDRESS_MAP_START(cpu_io_map , AS_IO , 8 , hp82937_io_card_device)
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x00 , 0x01) AM_DEVREADWRITE("xlator" , hp_1mb5_device , uc_r , uc_w)
AM_RANGE(0x03 , 0x03) AM_READWRITE(switch_r , latch_w)
ADDRESS_MAP_END
const tiny_rom_entry *hp82937_io_card_device::device_rom_region() const
{
return ROM_NAME(hp82937);
}
MACHINE_CONFIG_MEMBER(hp82937_io_card_device::device_add_mconfig)
MCFG_CPU_ADD("cpu" , I8049 , XTAL_11MHz)
MCFG_CPU_IO_MAP(cpu_io_map)
MCFG_MCS48_PORT_T0_IN_CB(READLINE(hp82937_io_card_device , t0_r))
MCFG_MCS48_PORT_T1_IN_CB(DEVREADLINE("xlator" , hp_1mb5_device , int_r))
MCFG_MCS48_PORT_P1_IN_CB(READ8(hp82937_io_card_device , p1_r))
MCFG_MCS48_PORT_P1_OUT_CB(WRITE8(hp82937_io_card_device , p1_w))
MCFG_MCS48_PORT_P2_IN_CB(READ8(hp82937_io_card_device , dio_r))
MCFG_MCS48_PORT_P2_OUT_CB(WRITE8(hp82937_io_card_device , dio_w))
MCFG_DEVICE_ADD("xlator" , HP_1MB5 , 0)
MCFG_1MB5_IRL_HANDLER(WRITELINE(hp82937_io_card_device , irl_w))
MCFG_1MB5_HALT_HANDLER(WRITELINE(hp82937_io_card_device , halt_w))
MCFG_1MB5_RESET_HANDLER(WRITELINE(hp82937_io_card_device , reset_w))
MCFG_IEEE488_SLOT_ADD("ieee_dev" , 0 , hp_ieee488_devices , nullptr)
MCFG_IEEE488_BUS_ADD()
MCFG_IEEE488_IFC_CALLBACK(WRITELINE(hp82937_io_card_device , ieee488_ctrl_w))
MCFG_IEEE488_ATN_CALLBACK(WRITELINE(hp82937_io_card_device , ieee488_ctrl_w))
MCFG_IEEE488_REN_CALLBACK(WRITELINE(hp82937_io_card_device , ieee488_ctrl_w))
MCFG_IEEE488_EOI_CALLBACK(WRITELINE(hp82937_io_card_device , ieee488_ctrl_w))
MACHINE_CONFIG_END
// device type definition
DEFINE_DEVICE_TYPE(HP82937_IO_CARD, hp82937_io_card_device, "hp82937", "HP82937 card")

View File

@ -0,0 +1,71 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
82937.h
82937 module (HPIB interface)
*********************************************************************/
#ifndef MAME_BUS_HP80_IO_82937_H
#define MAME_BUS_HP80_IO_82937_H
#pragma once
#include "hp80_io.h"
#include "cpu/mcs48/mcs48.h"
#include "bus/ieee488/ieee488.h"
#include "machine/1mb5.h"
class hp82937_io_card_device : public hp80_io_card_device
{
public:
// construction/destruction
hp82937_io_card_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ~hp82937_io_card_device();
virtual void install_read_write_handlers(address_space& space , uint16_t base_addr) override;
virtual void inten() override;
virtual void clear_service() override;
DECLARE_WRITE_LINE_MEMBER(reset_w);
DECLARE_READ_LINE_MEMBER(t0_r);
DECLARE_READ8_MEMBER(p1_r);
DECLARE_WRITE8_MEMBER(p1_w);
DECLARE_READ8_MEMBER(dio_r);
DECLARE_WRITE8_MEMBER(dio_w);
DECLARE_READ8_MEMBER(switch_r);
DECLARE_WRITE8_MEMBER(latch_w);
DECLARE_WRITE_LINE_MEMBER(ieee488_ctrl_w);
protected:
virtual void device_start() override;
virtual void device_reset() override;
// device-level overrides
virtual ioport_constructor device_input_ports() const override;
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
private:
required_device<i8049_device> m_cpu;
required_device<hp_1mb5_device> m_translator;
required_ioport m_sw1;
required_device<ieee488_device> m_ieee488;
bool m_dio_out; // U8-4
bool m_talker_out; // U7-6
bool m_iatn;
uint8_t m_latch; // U3
bool m_updating;
void update_data_out();
void update_signals();
};
// device type definition
DECLARE_DEVICE_TYPE(HP82937_IO_CARD, hp82937_io_card_device)
#endif // MAME_BUS_HP80_IO_82937_H

View File

@ -0,0 +1,150 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
hp80_io.cpp
I/O bus of HP80 systems
*********************************************************************/
#include "emu.h"
#include "hp80_io.h"
// Debugging
#define VERBOSE 0
#include "logmacro.h"
// device type definition
DEFINE_DEVICE_TYPE(HP80_IO_SLOT, hp80_io_slot_device, "hp80_io_slot", "HP80 I/O Slot")
// +-------------------+
// |hp80_io_slot_device|
// +-------------------+
hp80_io_slot_device::hp80_io_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, HP80_IO_SLOT, tag, owner, clock),
device_slot_interface(mconfig, *this),
m_irl_cb_func(*this),
m_halt_cb_func(*this),
m_slot_no(0)
{
}
hp80_io_slot_device::~hp80_io_slot_device()
{
}
void hp80_io_slot_device::device_start()
{
m_irl_cb_func.resolve_safe();
m_halt_cb_func.resolve_safe();
}
WRITE_LINE_MEMBER(hp80_io_slot_device::irl_w)
{
LOG("irl_w slot %u=%d\n" , m_slot_no , state);
m_irl_cb_func(m_slot_no , state , 0xff);
}
WRITE_LINE_MEMBER(hp80_io_slot_device::halt_w)
{
LOG("halt_w slot %u=%d\n" , m_slot_no , state);
m_halt_cb_func(m_slot_no , state , 0xff);
}
void hp80_io_slot_device::inten()
{
hp80_io_card_device *card = downcast<hp80_io_card_device*>(get_card_device());
if (card != nullptr) {
card->inten();
}
}
void hp80_io_slot_device::clear_service()
{
hp80_io_card_device *card = downcast<hp80_io_card_device*>(get_card_device());
if (card != nullptr) {
card->clear_service();
}
}
void hp80_io_slot_device::install_read_write_handlers(address_space& space)
{
hp80_io_card_device *card = downcast<hp80_io_card_device*>(get_card_device());
if (card != nullptr) {
card->install_read_write_handlers(space , get_base_addr());
}
}
uint8_t hp80_io_slot_device::get_sc() const
{
const hp80_io_card_device *card = downcast<hp80_io_card_device*>(get_card_device());
if (card != nullptr) {
return card->get_sc();
} else {
return 0;
}
}
uint16_t hp80_io_slot_device::get_base_addr() const
{
const hp80_io_card_device *card = downcast<hp80_io_card_device*>(get_card_device());
if (card != nullptr) {
uint16_t addr = ((uint16_t)(card->get_sc() - HP80_IO_FIRST_SC) << 1) | 0xff50;
return addr;
} else {
return 0;
}
}
// +-------------------+
// |hp80_io_card_device|
// +-------------------+
uint8_t hp80_io_card_device::get_sc() const
{
return m_select_code_port->read() + HP80_IO_FIRST_SC;
}
void hp80_io_card_device::inten()
{
}
void hp80_io_card_device::clear_service()
{
}
hp80_io_card_device::hp80_io_card_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
device_slot_card_interface(mconfig, *this),
m_select_code_port(*this , "SC")
{
}
hp80_io_card_device::~hp80_io_card_device()
{
}
WRITE_LINE_MEMBER(hp80_io_card_device::irl_w)
{
LOG("irl_w card=%d\n" , state);
hp80_io_slot_device *slot = downcast<hp80_io_slot_device *>(owner());
slot->irl_w(state);
}
WRITE_LINE_MEMBER(hp80_io_card_device::halt_w)
{
LOG("halt_w card=%d\n" , state);
hp80_io_slot_device *slot = downcast<hp80_io_slot_device *>(owner());
slot->halt_w(state);
}
#include "82937.h"
SLOT_INTERFACE_START(hp80_io_slot_devices)
SLOT_INTERFACE("82937_hpib" , HP82937_IO_CARD)
SLOT_INTERFACE_END

View File

@ -0,0 +1,107 @@
// license:BSD-3-Clause
// copyright-holders: F. Ulivi
/*********************************************************************
hp80_io.h
I/O bus of HP80 systems
*********************************************************************/
#ifndef MAME_BUS_HP80_IO_HP80_IO_H
#define MAME_BUS_HP80_IO_HP80_IO_H
#pragma once
#define MCFG_HP80_IO_SLOT_ADD(_tag , _idx) \
MCFG_DEVICE_ADD(_tag, HP80_IO_SLOT, 0) \
MCFG_DEVICE_SLOT_INTERFACE(hp80_io_slot_devices, nullptr, false) \
hp80_io_slot_device::set_slot_no(*device , _idx);
#define MCFG_HP80_IO_IRL_CB(_devcb) \
devcb = &hp80_io_slot_device::set_irl_cb_func(*device , DEVCB_##_devcb);
#define MCFG_HP80_IO_HALT_CB(_devcb) \
devcb = &hp80_io_slot_device::set_halt_cb_func(*device , DEVCB_##_devcb);
#define HP80_IO_FIRST_SC 3 // Lowest SC used by I/O cards
#define MCFG_HP80_IO_SC(_default_sc) \
PORT_START("SC") \
PORT_CONFNAME(0xf , (_default_sc) - HP80_IO_FIRST_SC , "Select Code") \
PORT_CONFSETTING(0 , "3")\
PORT_CONFSETTING(1 , "4")\
PORT_CONFSETTING(2 , "5")\
PORT_CONFSETTING(3 , "6")\
PORT_CONFSETTING(4 , "7")\
PORT_CONFSETTING(5 , "8")\
PORT_CONFSETTING(6 , "9")\
PORT_CONFSETTING(7 , "10")
class hp80_io_slot_device : public device_t,
public device_slot_interface
{
public:
// construction/destruction
hp80_io_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ~hp80_io_slot_device();
// static configuration helpers
static void set_slot_no(device_t &device, unsigned slot_no) { downcast<hp80_io_slot_device &>(device).m_slot_no = slot_no; }
// device-level overrides
virtual void device_start() override;
// Callback setups
template <class Object> static devcb_base &set_irl_cb_func(device_t &device, Object &&cb) { return downcast<hp80_io_slot_device &>(device).m_irl_cb_func.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_halt_cb_func(device_t &device, Object &&cb) { return downcast<hp80_io_slot_device &>(device).m_halt_cb_func.set_callback(std::forward<Object>(cb)); }
// SC getter
uint8_t get_sc() const;
uint16_t get_base_addr() const;
void install_read_write_handlers(address_space& space);
DECLARE_WRITE_LINE_MEMBER(irl_w);
DECLARE_WRITE_LINE_MEMBER(halt_w);
void inten();
void clear_service();
private:
devcb_write8 m_irl_cb_func;
devcb_write8 m_halt_cb_func;
unsigned m_slot_no;
};
class hp80_io_card_device : public device_t,
public device_slot_card_interface
{
public:
// SC getter
uint8_t get_sc() const;
virtual void install_read_write_handlers(address_space& space , uint16_t base_addr) = 0;
virtual void inten();
virtual void clear_service();
protected:
// construction/destruction
hp80_io_card_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual ~hp80_io_card_device();
required_ioport m_select_code_port;
// card device handling
DECLARE_WRITE_LINE_MEMBER(irl_w);
DECLARE_WRITE_LINE_MEMBER(halt_w);
};
// device type definition
DECLARE_DEVICE_TYPE(HP80_IO_SLOT, hp80_io_slot_device)
SLOT_INTERFACE_EXTERN(hp80_io_slot_devices);
#endif // MAME_BUS_HP80_IO_HP80_IO_H

View File

@ -484,6 +484,10 @@ WRITE8_MEMBER(hp9895_device::phi_dio_w)
WRITE_LINE_MEMBER(hp9895_device::phi_int_w)
{
m_cpu->set_input_line(INPUT_LINE_NMI , state);
if (state) {
// Ensure the event queue is emptied before executing any other instruction
m_cpu->yield();
}
}
READ8_MEMBER(hp9895_device::phi_reg_r)

View File

@ -0,0 +1,295 @@
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
/*********************************************************************
1mb5.cpp
HP-8x I/O Translator chip (1MB5-0101)
Reference for this chip:
HP, aug 79, 1MB5 Detailed specification - Translator chip
*********************************************************************/
#include "emu.h"
#include "1mb5.h"
// Debugging
#define VERBOSE 0
#include "logmacro.h"
// device type definition
DEFINE_DEVICE_TYPE(HP_1MB5, hp_1mb5_device, "hp_1mb5", "HP 1MB5")
// Bit manipulation
namespace {
static constexpr unsigned BIT_MASK(unsigned n)
{
return 1U << n;
}
template<typename T> void BIT_CLR(T& w , unsigned n)
{
w &= ~(T)BIT_MASK(n);
}
template<typename T> void BIT_SET(T& w , unsigned n)
{
w |= (T)BIT_MASK(n);
}
template<typename T> void COPY_BIT(bool bit , T& w , unsigned n)
{
if (bit) {
BIT_SET(w , n);
} else {
BIT_CLR(w , n);
}
}
}
hp_1mb5_device::hp_1mb5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig , HP_1MB5 , tag , owner , clock),
m_irl_handler(*this),
m_halt_handler(*this),
m_reset_handler(*this),
m_int_handler(*this)
{
}
READ8_MEMBER(hp_1mb5_device::cpu_r)
{
uint8_t res = 0;
switch (offset) {
case 0:
// Read SR
res = m_sr & 0x7e;
if (m_obf) {
BIT_SET(res , 7);
}
if (m_ibf) {
BIT_SET(res , 0);
}
break;
case 1:
// Read IB
res = m_ib;
m_ibf = false;
update_halt();
break;
}
//LOG("RD %u=%02x\n" , offset , res);
return res;
}
WRITE8_MEMBER(hp_1mb5_device::cpu_w)
{
//LOG("WR %u=%02x\n" , offset , data);
bool need_resched = false;
switch (offset) {
case 0:
// Write CR
m_cr = data;
need_resched |= set_reset(BIT(m_cr , 7));
need_resched |= set_int(!BIT(m_cr , 0));
break;
case 1:
// Write OB
m_ob = data;
m_obf = true;
update_halt();
break;
}
if (need_resched) {
LOG("resched %s\n" , space.device().tag());
space.device().execute().yield();
}
}
READ8_MEMBER(hp_1mb5_device::uc_r)
{
uint8_t res = 0;
bool need_resched = false;
switch (offset) {
case 0:
// Read CR
res = m_cr & 0x7e;
if (m_obf) {
BIT_SET(res , 7);
}
if (m_ibf) {
BIT_SET(res , 0);
}
break;
case 1:
// Read OB
res = m_ob;
m_obf = false;
need_resched |= update_halt();
break;
}
if (need_resched) {
LOG("resched %s\n" , space.device().tag());
space.device().execute().spin();
}
//LOG("RDU %u=%02x\n" , offset , res);
return res;
}
WRITE8_MEMBER(hp_1mb5_device::uc_w)
{
//LOG("WRU %u=%02x SR=%02x\n" , offset , data , m_sr);
bool need_resched = false;
switch (offset) {
case 0:
// Write SR
if (!BIT(m_sr , 0) && BIT(data , 0)) {
need_resched |= set_service(true);
}
m_sr = data;
m_hlten = BIT(m_sr , 7);
if (update_halt() && !m_halt) {
need_resched = true;
}
break;
case 1:
// Write IB
m_ib = data;
m_ibf = true;
need_resched |= update_halt();
break;
}
if (need_resched) {
LOG("resched %s\n" , space.device().tag());
space.device().execute().spin();
}
}
READ_LINE_MEMBER(hp_1mb5_device::irl_r)
{
return m_service;
}
READ_LINE_MEMBER(hp_1mb5_device::halt_r)
{
return m_halt;
}
READ_LINE_MEMBER(hp_1mb5_device::reset_r)
{
return m_reset;
}
READ_LINE_MEMBER(hp_1mb5_device::int_r)
{
return m_cint;
}
void hp_1mb5_device::inten()
{
// Enabling interrupts (i.e. writing to 0xff40) removes uC reset
set_reset(false);
}
void hp_1mb5_device::clear_service()
{
set_service(false);
}
void hp_1mb5_device::device_start()
{
m_irl_handler.resolve_safe();
m_halt_handler.resolve_safe();
m_reset_handler.resolve_safe();
m_int_handler.resolve_safe();
save_item(NAME(m_sr));
save_item(NAME(m_cr));
save_item(NAME(m_ib));
save_item(NAME(m_ob));
save_item(NAME(m_ibf));
save_item(NAME(m_obf));
save_item(NAME(m_hlten));
save_item(NAME(m_service));
save_item(NAME(m_cint));
save_item(NAME(m_reset));
save_item(NAME(m_halt));
}
void hp_1mb5_device::device_reset()
{
m_sr = 0;
m_cr = 0;
m_ib = 0;
m_ob = 0;
m_ibf = false;
m_obf = false;
m_hlten = false;
m_service = false;
m_cint = true;
m_reset = true;
m_halt = false;
m_irl_handler(false);
m_halt_handler(false);
m_reset_handler(true);
m_int_handler(true);
}
bool hp_1mb5_device::set_service(bool new_service)
{
if (new_service != m_service) {
m_service = new_service;
//LOG("irl=%d\n" , m_service);
m_irl_handler(m_service);
return true;
} else {
return false;
}
}
bool hp_1mb5_device::update_halt()
{
bool new_halt = m_hlten && m_obf && !m_ibf;
if (new_halt != m_halt) {
//LOG("HALT=%d\n" , new_halt);
m_halt = new_halt;
m_halt_handler(m_halt);
return true;
} else {
return false;
}
}
bool hp_1mb5_device::set_reset(bool new_reset)
{
if (new_reset != m_reset) {
m_reset = new_reset;
m_reset_handler(m_reset);
return true;
} else {
return false;
}
}
bool hp_1mb5_device::set_int(bool new_int)
{
if (new_int != m_cint) {
m_cint = new_int;
LOG("cint=%d\n" , m_cint);
m_int_handler(m_cint);
return true;
} else {
return false;
}
}

View File

@ -0,0 +1,95 @@
// license:BSD-3-Clause
// copyright-holders:F. Ulivi
/*********************************************************************
1mb5.h
HP-8x I/O Translator chip (1MB5-0101)
*********************************************************************/
#ifndef MAME_MACHINE_1MB5_H
#define MAME_MACHINE_1MB5_H
#pragma once
#define MCFG_1MB5_IRL_HANDLER(_devcb) \
devcb = &hp_1mb5_device::set_irl_handler(*device , DEVCB_##_devcb);
#define MCFG_1MB5_HALT_HANDLER(_devcb) \
devcb = &hp_1mb5_device::set_halt_handler(*device , DEVCB_##_devcb);
#define MCFG_1MB5_RESET_HANDLER(_devcb) \
devcb = &hp_1mb5_device::set_reset_handler(*device , DEVCB_##_devcb);
#define MCFG_1MB5_INT_HANDLER(_devcb) \
devcb = &hp_1mb5_device::set_int_handler(*device , DEVCB_##_devcb);
class hp_1mb5_device : public device_t
{
public:
// construction/destruction
hp_1mb5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// static configuration helpers
template <class Object> static devcb_base &set_irl_handler(device_t &device, Object &&cb) { return downcast<hp_1mb5_device &>(device).m_irl_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_halt_handler(device_t &device, Object &&cb) { return downcast<hp_1mb5_device &>(device).m_halt_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_reset_handler(device_t &device, Object &&cb) { return downcast<hp_1mb5_device &>(device).m_reset_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_int_handler(device_t &device, Object &&cb) { return downcast<hp_1mb5_device &>(device).m_int_handler.set_callback(std::forward<Object>(cb)); }
// CPU access
DECLARE_READ8_MEMBER(cpu_r);
DECLARE_WRITE8_MEMBER(cpu_w);
// uC access
DECLARE_READ8_MEMBER(uc_r);
DECLARE_WRITE8_MEMBER(uc_w);
// Signals to CPU
DECLARE_READ_LINE_MEMBER(irl_r);
DECLARE_READ_LINE_MEMBER(halt_r);
// Signals to uC
DECLARE_READ_LINE_MEMBER(reset_r);
DECLARE_READ_LINE_MEMBER(int_r);
// Interrupt enable
void inten();
// Interrupt clearing
void clear_service();
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
private:
devcb_write_line m_irl_handler;
devcb_write_line m_halt_handler;
devcb_write_line m_reset_handler;
devcb_write_line m_int_handler;
// Registers
uint8_t m_sr;
uint8_t m_cr;
uint8_t m_ib;
uint8_t m_ob;
bool m_ibf;
bool m_obf;
bool m_hlten;
bool m_service;
bool m_cint;
bool m_reset;
bool m_halt;
bool set_service(bool new_service);
bool update_halt();
bool set_reset(bool new_reset);
bool set_int(bool new_int);
};
// device type definition
DECLARE_DEVICE_TYPE(HP_1MB5, hp_1mb5_device)
#endif /* MAME_MACHINE_1MB5_H */

View File

@ -1246,7 +1246,7 @@ bool phi_device::if_cmd_received(uint8_t byte)
}
} else {
// command is a secondary address
if (m_t_state == PHI_T_ID1 && my_addr) {
if (m_t_state == PHI_T_ID1 && (m_l_state == PHI_L_LADS) == !!lon_msg() && my_addr) {
// Start IDENTIFY sequence
m_t_state = PHI_T_ID2;
} else if (m_t_state >= PHI_T_ID2 && m_t_state <= PHI_T_ID6 && !my_addr) {

View File

@ -19,6 +19,7 @@
#include "bus/hp80_optroms/hp80_optrom.h"
#include "softlist.h"
#include "machine/bankdev.h"
#include "bus/hp80_io/hp80_io.h"
// Debugging
#define VERBOSE 1
@ -72,7 +73,8 @@ static constexpr unsigned IRQ_KEYBOARD_BIT = 0;
static constexpr unsigned IRQ_TIMER0_BIT = 1;
static constexpr unsigned TIMER_COUNT = 4;
static constexpr unsigned IRQ_IOP0_BIT = IRQ_TIMER0_BIT + TIMER_COUNT;
static constexpr unsigned IOP_COUNT = 0;
// Maximum count of I/O processors (the same thing as count of I/O slots)
static constexpr unsigned IOP_COUNT = 4;
static constexpr unsigned IRQ_BIT_COUNT = IRQ_IOP0_BIT + IOP_COUNT;
static constexpr unsigned NO_IRQ = IRQ_BIT_COUNT;
@ -105,11 +107,17 @@ public:
DECLARE_READ8_MEMBER(clkdat_r);
DECLARE_WRITE8_MEMBER(clkdat_w);
DECLARE_WRITE8_MEMBER(rselec_w);
DECLARE_READ8_MEMBER(intrsc_r);
DECLARE_WRITE8_MEMBER(intrsc_w);
TIMER_DEVICE_CALLBACK_MEMBER(kb_scan);
TIMER_DEVICE_CALLBACK_MEMBER(vm_timer);
TIMER_DEVICE_CALLBACK_MEMBER(timer_update);
TIMER_DEVICE_CALLBACK_MEMBER(clk_busy_timer);
DECLARE_WRITE8_MEMBER(irl_w);
DECLARE_WRITE8_MEMBER(halt_w);
protected:
required_device<capricorn_cpu_device> m_cpu;
required_device<screen_device> m_screen;
@ -124,6 +132,7 @@ protected:
required_ioport m_io_modkeys;
required_device_array<hp80_optrom_slot_device , 6> m_rom_drawers;
required_device<address_map_bank_device> m_rombank;
required_device_array<hp80_io_slot_device , IOP_COUNT> m_io_slots;
// Character generator
required_region_ptr<uint8_t> m_chargen;
@ -137,11 +146,11 @@ protected:
uint8_t m_crt_read_byte;
uint8_t m_crt_write_byte;
bool m_global_int_en;
uint16_t m_int_req;
uint16_t m_int_serv;
unsigned m_top_pending;
uint16_t m_int_acked;
uint16_t m_int_en;
uint8_t m_halt_lines;
// State of keyboard
ioport_value m_kb_state[ 3 ];
@ -192,6 +201,7 @@ hp85_state::hp85_state(const machine_config &mconfig, device_type type, const ch
m_io_modkeys(*this, "MODKEYS"),
m_rom_drawers(*this , "drawer%u" , 1),
m_rombank(*this , "rombank"),
m_io_slots(*this , "slot%u" , 1),
m_chargen(*this , "chargen")
{
}
@ -210,7 +220,6 @@ void hp85_state::machine_reset()
m_crt_ctl = BIT_MASK(CRT_CTL_POWERDN_BIT) | BIT_MASK(CRT_CTL_WIPEOUT_BIT);
m_crt_read_byte = 0;
m_crt_write_byte = 0;
m_int_req = 0;
m_int_serv = 0;
m_top_pending = NO_IRQ;
m_int_acked = 0;
@ -235,6 +244,8 @@ void hp85_state::machine_reset()
m_timer_idx = 0;
m_clk_busy = false;
update_irl();
m_halt_lines = 0;
m_cpu->set_input_line(INPUT_LINE_HALT , CLEAR_LINE);
// Load optional ROMs (if any)
// All entries in rombanks [01..FF] initially not present
@ -245,6 +256,12 @@ void hp85_state::machine_reset()
}
// Clear RSELEC
m_rombank->set_bank(0xff);
// Mount I/O slots in address space
m_cpu->space(AS_PROGRAM).unmap_readwrite(0xff50 , 0xff5f);
for (auto& io : m_io_slots) {
io->install_read_write_handlers(m_cpu->space(AS_PROGRAM));
}
}
uint32_t hp85_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
@ -307,13 +324,24 @@ static const uint8_t vector_table[] = {
0x08, // Timer 0
0x0a, // Timer 1
0x0c, // Timer 2
0x0e // Timer 3
0x0e, // Timer 3
0x10, // Slot 1
0x10, // Slot 2
0x10, // Slot 3
0x10 // Slot 4
};
IRQ_CALLBACK_MEMBER(hp85_state::irq_callback)
{
logerror("IRQ ACK %u\n" , m_top_pending);
BIT_SET(m_int_acked , m_top_pending);
if (m_top_pending > IRQ_IOP0_BIT && m_top_pending < IRQ_BIT_COUNT) {
// Interrupts are disabled in all I/O translators of higher priority than
// the one being serviced
for (unsigned i = m_top_pending - 1; i >= IRQ_IOP0_BIT; i--) {
irq_en_w(i , false);
}
}
update_irl();
return vector_table[ m_top_pending ];
}
@ -539,6 +567,30 @@ WRITE8_MEMBER(hp85_state::rselec_w)
m_rombank->set_bank(data);
}
READ8_MEMBER(hp85_state::intrsc_r)
{
if (m_top_pending >= IRQ_IOP0_BIT && m_top_pending < IRQ_BIT_COUNT && BIT(m_int_acked , m_top_pending)) {
return (uint8_t)m_io_slots[ m_top_pending - IRQ_IOP0_BIT ]->get_base_addr();
} else {
// Probably..
return 0xff;
}
}
WRITE8_MEMBER(hp85_state::intrsc_w)
{
if (m_top_pending >= IRQ_IOP0_BIT && m_top_pending < IRQ_BIT_COUNT && BIT(m_int_acked , m_top_pending)) {
// Clear interrupt request in the slot being serviced
m_io_slots[ m_top_pending - IRQ_IOP0_BIT ]->clear_service();
}
for (auto& iop: m_io_slots) {
iop->inten();
}
for (unsigned i = IRQ_IOP0_BIT; i < (IRQ_IOP0_BIT + IOP_COUNT); i++) {
irq_en_w(i , true);
}
}
// Outer index: key position [0..79] = r * 8 + c
// Inner index: SHIFT state (0 = no SHIFT, 1 = SHIFT)
static const uint8_t keyboard_table[ 80 ][ 2 ] = {
@ -790,6 +842,24 @@ TIMER_DEVICE_CALLBACK_MEMBER(hp85_state::clk_busy_timer)
m_clk_busy = false;
}
WRITE8_MEMBER(hp85_state::irl_w)
{
//LOG("irl_w %u=%u\n" , offset , data);
irq_w(offset + IRQ_IOP0_BIT , data != 0);
}
WRITE8_MEMBER(hp85_state::halt_w)
{
//LOG("halt_w %u=%u\n" , offset , data);
bool prev_halt = m_halt_lines != 0;
COPY_BIT(data != 0 , m_halt_lines , offset);
bool new_halt = m_halt_lines != 0;
if (prev_halt != new_halt) {
LOG("halt=%d hl=%x\n" , new_halt , m_halt_lines);
m_cpu->set_input_line(INPUT_LINE_HALT , new_halt);
}
}
attotime hp85_state::time_to_video_mem_availability() const
{
if (BIT(m_crt_ctl , CRT_CTL_WIPEOUT_BIT) || BIT(m_crt_ctl , CRT_CTL_POWERDN_BIT)) {
@ -880,6 +950,7 @@ void hp85_state::video_mem_write()
void hp85_state::irq_w(unsigned n_irq , bool state)
{
//LOG("irq_w %u=%d GIE=%d SRV=%03x ACK=%03x IE=%03x\n" , n_irq , state , m_global_int_en , m_int_serv , m_int_acked , m_int_en);
if (state && !BIT(m_int_serv , n_irq)) {
// Set service request
BIT_SET(m_int_serv , n_irq);
@ -908,6 +979,7 @@ void hp85_state::update_int_bits()
void hp85_state::update_irl()
{
//LOG("irl GIE=%d top=%u ACK=%03x\n" , m_global_int_en , m_top_pending , m_int_acked);
m_cpu->set_input_line(0 , m_global_int_en && m_top_pending < IRQ_BIT_COUNT && !BIT(m_int_acked , m_top_pending));
}
@ -1024,6 +1096,7 @@ static ADDRESS_MAP_START(cpu_mem_map , AS_PROGRAM , 8 , hp85_state)
AM_RANGE(0xff0a , 0xff0a) AM_READWRITE(clksts_r , clksts_w)
AM_RANGE(0xff0b , 0xff0b) AM_READWRITE(clkdat_r , clkdat_w)
AM_RANGE(0xff18 , 0xff18) AM_WRITE(rselec_w)
AM_RANGE(0xff40 , 0xff40) AM_READWRITE(intrsc_r , intrsc_w)
ADDRESS_MAP_END
static ADDRESS_MAP_START(rombank_mem_map , AS_PROGRAM , 8 , hp85_state)
@ -1042,7 +1115,7 @@ static MACHINE_CONFIG_START(hp85)
MCFG_ADDRESS_MAP_BANK_ENDIANNESS(ENDIANNESS_LITTLE)
MCFG_ADDRESS_MAP_BANK_DATABUS_WIDTH(8)
MCFG_ADDRESS_MAP_BANK_ADDRBUS_WIDTH(21)
MCFG_ADDRESS_MAP_BANK_STRIDE(0x2000)
MCFG_ADDRESS_MAP_BANK_STRIDE(HP80_OPTROM_SIZE)
MCFG_SCREEN_ADD("screen" , RASTER)
MCFG_SCREEN_RAW_PARAMS(MASTER_CLOCK / 2 , 312 , 0 , 256 , 256 , 0 , 192)
@ -1085,6 +1158,20 @@ static MACHINE_CONFIG_START(hp85)
MCFG_DEVICE_ADD("drawer6", HP80_OPTROM_SLOT, 0)
MCFG_DEVICE_SLOT_INTERFACE(hp80_optrom_slot_device, NULL, false)
// I/O slots
MCFG_HP80_IO_SLOT_ADD("slot1" , 0)
MCFG_HP80_IO_IRL_CB(WRITE8(hp85_state , irl_w))
MCFG_HP80_IO_HALT_CB(WRITE8(hp85_state , halt_w))
MCFG_HP80_IO_SLOT_ADD("slot2" , 1)
MCFG_HP80_IO_IRL_CB(WRITE8(hp85_state , irl_w))
MCFG_HP80_IO_HALT_CB(WRITE8(hp85_state , halt_w))
MCFG_HP80_IO_SLOT_ADD("slot3" , 2)
MCFG_HP80_IO_IRL_CB(WRITE8(hp85_state , irl_w))
MCFG_HP80_IO_HALT_CB(WRITE8(hp85_state , halt_w))
MCFG_HP80_IO_SLOT_ADD("slot4" , 3)
MCFG_HP80_IO_IRL_CB(WRITE8(hp85_state , irl_w))
MCFG_HP80_IO_HALT_CB(WRITE8(hp85_state , halt_w))
MCFG_SOFTWARE_LIST_ADD("optrom_list" , "hp85_rom")
MACHINE_CONFIG_END