summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author fulivi <fulivi@users.noreply.github.com>2018-03-11 17:22:24 +0100
committer fulivi <fulivi@users.noreply.github.com>2018-03-11 17:22:24 +0100
commit01e86e4cecf4c4d1fbf6ba0d2146af76eec84152 (patch)
tree31ce4d44d6d22ec5b0ca2341424496a89805ff0a
parent81a35fb46e22d8efcc19d92ae7b85656b2e36c13 (diff)
hp64k: added support for HPIB bus. Extensive improvement of PHI emulation.
-rw-r--r--src/devices/bus/ieee488/hp9895.cpp1
-rw-r--r--src/devices/bus/ieee488/ieee488.cpp21
-rw-r--r--src/devices/bus/ieee488/ieee488.h8
-rw-r--r--src/devices/machine/phi.cpp579
-rw-r--r--src/devices/machine/phi.h67
-rw-r--r--src/mame/drivers/hp64k.cpp78
6 files changed, 493 insertions, 261 deletions
diff --git a/src/devices/bus/ieee488/hp9895.cpp b/src/devices/bus/ieee488/hp9895.cpp
index 2e477775747..d6d77493d49 100644
--- a/src/devices/bus/ieee488/hp9895.cpp
+++ b/src/devices/bus/ieee488/hp9895.cpp
@@ -899,6 +899,7 @@ MACHINE_CONFIG_START(hp9895_device::device_add_mconfig)
MCFG_PHI_REN_WRITE_CB(WRITELINE(hp9895_device , phi_ren_w))
MCFG_PHI_DIO_READWRITE_CB(READ8(hp9895_device , phi_dio_r) , WRITE8(hp9895_device , phi_dio_w))
MCFG_PHI_INT_WRITE_CB(WRITELINE(hp9895_device , phi_int_w))
+ MCFG_PHI_SYS_CNTRL_READ_CB(GND)
MCFG_FLOPPY_DRIVE_ADD("floppy0" , hp9895_floppies , "8dsdd" , hp9895_floppy_formats)
MCFG_SLOT_FIXED(true)
diff --git a/src/devices/bus/ieee488/ieee488.cpp b/src/devices/bus/ieee488/ieee488.cpp
index e224419c408..97f82f199ac 100644
--- a/src/devices/bus/ieee488/ieee488.cpp
+++ b/src/devices/bus/ieee488/ieee488.cpp
@@ -112,6 +112,7 @@ ieee488_device::ieee488_device(const machine_config &mconfig, const char *tag, d
m_write_srq(*this),
m_write_atn(*this),
m_write_ren(*this),
+ m_write_dio(*this),
m_dio(0xff)
{
for (auto & elem : m_line)
@@ -136,6 +137,7 @@ void ieee488_device::device_start()
m_write_srq.resolve_safe();
m_write_atn.resolve_safe();
m_write_ren.resolve_safe();
+ m_write_dio.resolve_safe();
}
@@ -320,11 +322,16 @@ int ieee488_device::get_signal(int signal)
void ieee488_device::set_data(device_t *device, uint8_t data)
{
+ bool changed = false;
+ uint8_t old_state = get_data();
+
if (device == this)
{
if (LOG) logerror("%s IEEE488: '%s' DIO %02x\n", machine().describe_context(), tag(), data);
-
- m_dio = data;
+ if (m_dio != data) {
+ m_dio = data;
+ changed = true;
+ }
}
else
{
@@ -338,12 +345,22 @@ void ieee488_device::set_data(device_t *device, uint8_t data)
{
if (LOG) logerror("%s IEEE488: '%s' DIO %02x\n", machine().describe_context(), device->tag(), data);
entry->m_dio = data;
+ changed = true;
}
}
entry = entry->next();
}
}
+
+ if (!changed) {
+ return;
+ }
+
+ uint8_t new_state = get_data();
+ if (old_state != new_state) {
+ m_write_dio(new_state);
+ }
}
diff --git a/src/devices/bus/ieee488/ieee488.h b/src/devices/bus/ieee488/ieee488.h
index c5dbb770e55..872963f1398 100644
--- a/src/devices/bus/ieee488/ieee488.h
+++ b/src/devices/bus/ieee488/ieee488.h
@@ -55,6 +55,12 @@
#define MCFG_IEEE488_REN_CALLBACK(_write) \
devcb = &downcast<ieee488_device *>(device)->set_ren_callback(DEVCB_##_write);
+// This CB reports changes to the DIO lines on the bus (whose value comes from
+// ANDing the DIO lines of each device on the bus)
+// This CB is needed by those controllers that start a parallel poll and wait
+// for some condition to be set by devices on the DIO lines (e.g. PHI controller).
+#define MCFG_IEEE488_DIO_CALLBACK(_write) \
+ devcb = &downcast<ieee488_device *>(device)->set_dio_callback(DEVCB_##_write);
#define MCFG_IEEE488_SLOT_ADD(_tag, _address, _slot_intf, _def_slot) \
MCFG_DEVICE_ADD(_tag, IEEE488_SLOT, 0) \
@@ -99,6 +105,7 @@ public:
template <class Object> devcb_base &set_srq_callback(Object &&cb) { return m_write_srq.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_atn_callback(Object &&cb) { return m_write_atn.set_callback(std::forward<Object>(cb)); }
template <class Object> devcb_base &set_ren_callback(Object &&cb) { return m_write_ren.set_callback(std::forward<Object>(cb)); }
+ template <class Object> devcb_base &set_dio_callback(Object &&cb) { return m_write_dio.set_callback(std::forward<Object>(cb)); }
void add_device(ieee488_slot_device *slot, device_t *target);
@@ -180,6 +187,7 @@ private:
devcb_write_line m_write_srq;
devcb_write_line m_write_atn;
devcb_write_line m_write_ren;
+ devcb_write8 m_write_dio;
void set_signal(device_t *device, int signal, int state);
int get_signal(int signal);
diff --git a/src/devices/machine/phi.cpp b/src/devices/machine/phi.cpp
index e86a7bb72ce..864ab7df44b 100644
--- a/src/devices/machine/phi.cpp
+++ b/src/devices/machine/phi.cpp
@@ -31,15 +31,33 @@
#include "phi.h"
// Debugging
-#define VERBOSE 1
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
-#define VERBOSE_0 0
-#define LOG_0(x) do { if (VERBOSE_0) logerror x; } while (0)
+#include "logmacro.h"
+#define LOG_NOISY_MASK (LOG_GENERAL << 1)
+#define LOG_NOISY(...) LOGMASKED(LOG_NOISY_MASK, __VA_ARGS__)
+#define LOG_REG_MASK (LOG_NOISY_MASK << 1)
+#define LOG_REG(...) LOGMASKED(LOG_REG_MASK, __VA_ARGS__)
+#define LOG_INT_MASK (LOG_REG_MASK << 1)
+#define LOG_INT(...) LOGMASKED(LOG_INT_MASK, __VA_ARGS__)
+#undef VERBOSE
+#define VERBOSE LOG_GENERAL
+
+// Bit manipulation
+namespace {
+ template<typename T> constexpr T BIT_MASK(unsigned n)
+ {
+ return (T)1U << n;
+ }
+
+ template<typename T> void BIT_CLR(T& w , unsigned n)
+ {
+ w &= ~BIT_MASK<T>(n);
+ }
-// Macros to clear/set single bits
-#define BIT_MASK(n) (1U << (n))
-#define BIT_CLR(w , n) ((w) &= ~BIT_MASK(n))
-#define BIT_SET(w , n) ((w) |= BIT_MASK(n))
+ template<typename T> void BIT_SET(T& w , unsigned n)
+ {
+ w |= BIT_MASK<T>(n);
+ }
+}
// Timers
enum {
@@ -68,103 +86,102 @@ enum {
};
// All valid bits in registers
-#define REG_ALL_MASK 0xc0ff
+constexpr uint16_t REG_ALL_MASK = 0xc0ff;
// D0 & D1 bits
-#define REG_D0D1_MASK 0xc000 // Mask of D0/D1 bits
-#define REG_D0D1_SHIFT 14 // Position of D0/D1 bits
+constexpr uint16_t REG_D0D1_MASK = 0xc000; // Mask of D0/D1 bits
+constexpr unsigned REG_D0D1_SHIFT = 14; // Position of D0/D1 bits
// D8-D15 bits
-#define REG_D08D15_MASK 0xff // Mask of D8:D15 bits
+constexpr uint16_t REG_D08D15_MASK = 0xff; // Mask of D8:D15 bits
// Bits in INT_COND & INT_MASK
-#define REG_INT_DEV_CLEAR_BIT 0 // Device clear
-#define REG_INT_FIFO_IDLE_BIT 1 // FIFO idle
-#define REG_INT_FIFO_AV_BIT 2 // FIFO bytes available
-#define REG_INT_FIFO_ROOM_BIT 3 // FIFO room available
-#define REG_INT_SRQ_BIT 4 // Service request
-#define REG_INT_PP_RESPONSE_BIT 5 // PP response
-#define REG_INT_PROC_ABORT_BIT 6 // Processor handshake abort
-#define REG_INT_STATUS_CH_BIT 7 // Status change
-#define REG_INT_PARITY_ERR_BIT 14 // Parity error
-#define REG_INT_PENDING_BIT 15 // Interrupt pending
-#define REG_INT_CLEARABLE_MASK 0x40c1 // Mask of clearable bits
-#define REG_INT_STATE_MASK 0x803e // Mask of "state" bits
+constexpr unsigned REG_INT_DEV_CLEAR_BIT = 0; // Device clear
+constexpr unsigned REG_INT_FIFO_IDLE_BIT = 1; // FIFO idle
+constexpr unsigned REG_INT_FIFO_AV_BIT = 2; // FIFO bytes available
+constexpr unsigned REG_INT_FIFO_ROOM_BIT = 3; // FIFO room available
+constexpr unsigned REG_INT_SRQ_BIT = 4; // Service request
+constexpr unsigned REG_INT_PP_RESPONSE_BIT = 5; // PP response
+constexpr unsigned REG_INT_PROC_ABORT_BIT = 6; // Processor handshake abort
+constexpr unsigned REG_INT_STATUS_CH_BIT = 7; // Status change
+constexpr unsigned REG_INT_PARITY_ERR_BIT = 14; // Parity error
+constexpr unsigned REG_INT_PENDING_BIT = 15; // Interrupt pending
+constexpr uint16_t REG_INT_CLEARABLE_MASK = 0x40c1; // Mask of clearable bits
+constexpr uint16_t REG_INT_STATE_MASK = 0x803e; // Mask of "state" bits
// Bits in inbound FIFO
-#define REG_IFIFO_NORMAL_MASK 0x0000 // Mask of D0/D1 bits for "normal" bytes
-#define REG_IFIFO_CNT_EXP_MASK 0x8000 // Mask for a byte that caused byte count to expire
-#define REG_IFIFO_LAST_MASK 0xc000 // Mask for last byte in a record
-#define REG_IFIFO_2_ADDR_MASK 0x4000 // Mask for secondary addresses
-#define REG_IFIFO_TALK_BIT 5 // Bit of "talk" flag
+constexpr uint16_t REG_IFIFO_NORMAL_MASK = 0x0000; // Mask of D0/D1 bits for "normal" bytes
+constexpr uint16_t REG_IFIFO_CNT_EXP_MASK = 0x8000; // Mask for a byte that caused byte count to expire
+constexpr uint16_t REG_IFIFO_LAST_MASK = 0xc000; // Mask for last byte in a record
+constexpr uint16_t REG_IFIFO_2_ADDR_MASK = 0x4000; // Mask for secondary addresses
+constexpr unsigned REG_IFIFO_TALK_BIT = 5; // Bit of "talk" flag
// Bits in outbound FIFO
-#define REG_OFIFO_SPECIAL_BIT 14 // Bit to discriminate between normal bytes and the rest
-#define REG_OFIFO_END_BIT 15 // Bit of EOI
-#define REG_OFIFO_IFCMD_MASK 0x4000 // Mask of interface commands
-#define REG_OFIFO_UNCNT_MASK 0xc000 // Mask of uncounted transfer enable
-#define REG_OFIFO_XFER_EN_MASK 0x0000 // Mask of byte transfer enable
-#define REG_OFIFO_LF_INH_BIT 15 // Bit of LF detection inhibit
+constexpr unsigned REG_OFIFO_SPECIAL_BIT = 14; // Bit to discriminate between normal bytes and the rest
+constexpr unsigned REG_OFIFO_END_BIT = 15; // Bit of EOI
+constexpr uint16_t REG_OFIFO_IFCMD_MASK = 0x4000; // Mask of interface commands
+constexpr uint16_t REG_OFIFO_UNCNT_MASK = 0xc000; // Mask of uncounted transfer enable
+constexpr unsigned REG_OFIFO_LF_INH_BIT = 15; // Bit of LF detection inhibit
// Bits in status register
-#define REG_STATUS_DATA_FREEZE_BIT 0 // Outbound data freeze
-#define REG_STATUS_LISTEN_BIT 1 // Addressed to listen
-#define REG_STATUS_TALK_BIT 2 // Addressed to talk or identify
-#define REG_STATUS_SYS_CTRL_BIT 3 // System controller
-#define REG_STATUS_CONTROLLER_BIT 4 // Current controller
-#define REG_STATUS_REMOTE_BIT 5 // Remote state
-#define REG_STATUS_D0D1_BIT 6 // D0/D1 bit access
-#define REG_STATUS_STATE_MASK 0x3e // Mask of "state" bits
+constexpr unsigned REG_STATUS_DATA_FREEZE_BIT = 0; // Outbound data freeze
+constexpr unsigned REG_STATUS_LISTEN_BIT = 1; // Addressed to listen
+constexpr unsigned REG_STATUS_TALK_BIT = 2; // Addressed to talk or identify
+constexpr unsigned REG_STATUS_SYS_CTRL_BIT = 3; // System controller
+constexpr unsigned REG_STATUS_CONTROLLER_BIT = 4; // Current controller
+constexpr unsigned REG_STATUS_REMOTE_BIT = 5; // Remote state
+constexpr unsigned REG_STATUS_D0D1_BIT = 6; // D0/D1 bit access
+constexpr uint16_t REG_STATUS_STATE_MASK = 0x3e; // Mask of "state" bits
// Bits in control register
-#define REG_CTRL_INIT_OFIFO_BIT 0 // Initialize outbound FIFO
-#define REG_CTRL_DMA_FIFO_BIT 1 // DMA FIFO selection
-#define REG_CTRL_SERVICE_REQ_BIT 2 // Request service
-#define REG_CTRL_PP_RESPONSE_BIT 3 // Respond to PP
-#define REG_CTRL_IFC_BIT 4 // IFC value
-#define REG_CTRL_REN_BIT 5 // REN value
-#define REG_CTRL_PAR_FREEZE_BIT 6 // Parity freeze
-#define REG_CTRL_8BIT_PROC_BIT 7 // 8-bit processor
+constexpr unsigned REG_CTRL_INIT_OFIFO_BIT = 0; // Initialize outbound FIFO
+constexpr unsigned REG_CTRL_DMA_FIFO_BIT = 1; // DMA FIFO selection
+constexpr unsigned REG_CTRL_SERVICE_REQ_BIT = 2; // Request service
+constexpr unsigned REG_CTRL_PP_RESPONSE_BIT = 3; // Respond to PP
+constexpr unsigned REG_CTRL_IFC_BIT = 4; // IFC value
+constexpr unsigned REG_CTRL_REN_BIT = 5; // REN value
+constexpr unsigned REG_CTRL_PAR_FREEZE_BIT = 6; // Parity freeze
+constexpr unsigned REG_CTRL_8BIT_PROC_BIT = 7; // 8-bit processor
// Bits in address register
-#define REG_ADDR_HPIB_ADDR_BIT 0 // HPIB address
-#define REG_ADDR_LA_BIT 5 // Listen always
-#define REG_ADDR_TA_BIT 6 // Talk always
-#define REG_ADDR_ONLINE_BIT 7 // Online
+constexpr unsigned REG_ADDR_HPIB_ADDR_BIT = 0; // HPIB address LSB
+constexpr unsigned REG_ADDR_LA_BIT = 5; // Listen always
+constexpr unsigned REG_ADDR_TA_BIT = 6; // Talk always
+constexpr unsigned REG_ADDR_ONLINE_BIT = 7; // Online
// Interface commands
-#define IFCMD_MASK 0x7f // Mask of interface commands
-#define IFCMD_DCL 0x14 // Device clear
-#define IFCMD_GET 0x08 // Group execute trigger
-#define IFCMD_GTL 0x01 // Go to local
-#define IFCMD_LLO 0x11 // Local lock-out
-#define IFCMD_AG_MASK 0x60 // Mask of bits identifying address group commands
-#define IFCMD_ADDR_MASK 0x1f // Mask of address in AG commands
-#define IFCMD_LAG_VALUE 0x20 // Value of LAG commands
-#define IFCMD_TAG_VALUE 0x40 // Value of TAG commands
-#define IFCMD_SCG_VALUE 0x60 // Value of SCG commands
-#define IFCMD_PPC 0x05 // Parallel poll configure
-#define IFCMD_PPX_MASK 0x70 // Mask of PPE/PPD commands
-#define IFCMD_PPE_VALUE 0x60 // Parallel poll enable
-#define IFCMD_PPE_S_BIT 3 // Position of "S" bit in PPE
-#define IFCMD_PPE_PPR_MASK 7 // Mask in PPE of PPR msg no.
-#define IFCMD_PPD_VALUE 0x70 // Parallel poll disable
-#define IFCMD_PPU 0x15 // Parallel poll unconfigure
-#define IFCMD_SDC 0x04 // Selected device clear
-#define IFCMD_SPD 0x19 // Serial poll disable
-#define IFCMD_SPE 0x18 // Serial poll enable
-#define IFCMD_TCT 0x09 // Take control
-#define IFCMD_UNL 0x3f // Unlisten
-#define IFCMD_UNT 0x5f // Untalk
+constexpr uint8_t IFCMD_MASK = 0x7f; // Mask of interface commands
+constexpr uint8_t IFCMD_DCL = 0x14; // Device clear
+constexpr uint8_t IFCMD_GET = 0x08; // Group execute trigger
+constexpr uint8_t IFCMD_GTL = 0x01; // Go to local
+constexpr uint8_t IFCMD_LLO = 0x11; // Local lock-out
+constexpr uint8_t IFCMD_AG_MASK = 0x60; // Mask of bits identifying address group commands
+constexpr uint8_t IFCMD_ADDR_MASK = 0x1f; // Mask of address in AG commands
+constexpr uint8_t IFCMD_LAG_VALUE = 0x20; // Value of LAG commands
+constexpr uint8_t IFCMD_TAG_VALUE = 0x40; // Value of TAG commands
+constexpr uint8_t IFCMD_SCG_VALUE = 0x60; // Value of SCG commands
+constexpr uint8_t IFCMD_PPC = 0x05; // Parallel poll configure
+constexpr uint8_t IFCMD_PPX_MASK = 0x70; // Mask of PPE/PPD commands
+constexpr uint8_t IFCMD_PPE_VALUE = 0x60; // Parallel poll enable
+constexpr unsigned IFCMD_PPE_S_BIT = 3; // Position of "S" bit in PPE
+constexpr uint8_t IFCMD_PPE_PPR_MASK = 7; // Mask in PPE of PPR msg no.
+constexpr uint8_t IFCMD_PPD_VALUE = 0x70; // Parallel poll disable
+constexpr uint8_t IFCMD_PPU = 0x15; // Parallel poll unconfigure
+constexpr uint8_t IFCMD_SDC = 0x04; // Selected device clear
+constexpr uint8_t IFCMD_SPD = 0x19; // Serial poll disable
+constexpr uint8_t IFCMD_SPE = 0x18; // Serial poll enable
+constexpr uint8_t IFCMD_TCT = 0x09; // Take control
+constexpr uint8_t IFCMD_UNL = 0x3f; // Unlisten
+constexpr uint8_t IFCMD_UNT = 0x5f; // Untalk
// Delays
-#define DELAY_T1 2000 // T1: 2 us
-#define DELAY_T7 500 // T7: 0.5 us
-#define DELAY_T9 1500 // T9: 1.5 us
-#define DELAY_T10 1500 // T10: 1.5 us
+constexpr unsigned DELAY_T1 = 2000; // T1: 2 us
+constexpr unsigned DELAY_T7 = 500; // T7: 0.5 us
+constexpr unsigned DELAY_T9 = 1500; // T9: 1.5 us
+constexpr unsigned DELAY_T10 = 1500; // T10: 1.5 us
// Controller address
-#define CONTROLLER_ADDR 0x1e // PHI always has this address when it's a controller
+constexpr uint8_t CONTROLLER_ADDR = 0x1e; // PHI always has this address when it's a system controller
// Device type definition
DEFINE_DEVICE_TYPE(PHI, phi_device, "hp_phi", "HP Processor-to-HPIB Interface")
@@ -184,7 +201,8 @@ phi_device::phi_device(const machine_config &mconfig, device_type type, const ch
devcb_write_line(*this),
devcb_write_line(*this) },
m_int_write_func(*this),
- m_dmarq_write_func(*this)
+ m_dmarq_write_func(*this),
+ m_sys_cntrl_read_func(*this)
{
}
@@ -233,21 +251,25 @@ WRITE_LINE_MEMBER(phi_device::ren_w)
set_ext_signal(PHI_488_REN , state);
}
+WRITE8_MEMBER(phi_device::bus_dio_w)
+{
+ update_pp();
+}
void phi_device::set_ext_signal(phi_488_signal_t signal , int state)
{
state = !state;
if (m_ext_signals[ signal ] != state) {
m_ext_signals[ signal ] = state;
- LOG_0(("EXT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
- m_ext_signals[ PHI_488_EOI ] ,
- m_ext_signals[ PHI_488_DAV ] ,
- m_ext_signals[ PHI_488_NRFD ] ,
- m_ext_signals[ PHI_488_NDAC ] ,
- m_ext_signals[ PHI_488_IFC ] ,
- m_ext_signals[ PHI_488_SRQ ] ,
- m_ext_signals[ PHI_488_ATN ] ,
- m_ext_signals[ PHI_488_REN ]));
+ LOG_NOISY("EXT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
+ m_ext_signals[ PHI_488_EOI ] ,
+ m_ext_signals[ PHI_488_DAV ] ,
+ m_ext_signals[ PHI_488_NRFD ] ,
+ m_ext_signals[ PHI_488_NDAC ] ,
+ m_ext_signals[ PHI_488_IFC ] ,
+ m_ext_signals[ PHI_488_SRQ ] ,
+ m_ext_signals[ PHI_488_ATN ] ,
+ m_ext_signals[ PHI_488_REN ]);
update_fsm();
}
}
@@ -271,10 +293,13 @@ READ16_MEMBER(phi_device::reg16_r)
break;
case REG_R_INBOUND_FIFO:
- // TODO: read from PP response
if (m_fifo_in.empty()) {
- BIT_SET(m_reg_int_cond, REG_INT_PROC_ABORT_BIT);
- res = 0;
+ if (m_c_state == PHI_C_CPPS) {
+ res = get_pp_response();
+ } else {
+ BIT_SET(m_reg_int_cond, REG_INT_PROC_ABORT_BIT);
+ res = 0;
+ }
} else {
res = m_fifo_in.dequeue();
}
@@ -303,7 +328,7 @@ READ16_MEMBER(phi_device::reg16_r)
default:
res = 0;
- LOG(("Reading from unmapped address (%u)\n", offset));
+ LOG("Reading from unmapped address (%u)\n", offset);
break;
};
@@ -313,7 +338,7 @@ READ16_MEMBER(phi_device::reg16_r)
((res & REG_D0D1_MASK) >> (REG_D0D1_SHIFT - REG_STATUS_D0D1_BIT));
}
- //LOG(("R %u=%04x\n" , offset , res));
+ LOG_REG("R %u=%04x\n" , offset , res);
return res;
}
@@ -341,11 +366,12 @@ void phi_device::device_start()
save_item(NAME(m_t_spms));
save_item(NAME(m_l_state));
save_item(NAME(m_sr_state));
+ save_item(NAME(m_rl_rems));
save_item(NAME(m_pp_state));
- save_item(NAME(m_pp_pacs));
save_item(NAME(m_ppr_msg));
save_item(NAME(m_s_sense));
save_item(NAME(m_c_state));
+ save_item(NAME(m_sa_state));
save_item(NAME(m_be_counter));
save_item(NAME(m_reg_status));
save_item(NAME(m_reg_int_cond));
@@ -363,6 +389,7 @@ void phi_device::device_start()
}
m_int_write_func.resolve_safe();
m_dmarq_write_func.resolve_safe();
+ m_sys_cntrl_read_func.resolve_safe(0);
m_sh_dly_timer = timer_alloc(SH_DELAY_TMR_ID);
m_c_dly_timer = timer_alloc(C_DELAY_TMR_ID);
@@ -391,6 +418,10 @@ void phi_device::device_reset()
m_reg_address = 0;
m_fifo_in.clear();
m_fifo_out.clear();
+ m_int_line = false;
+ m_int_write_func(false);
+ m_dmarq_line = false;
+ m_dmarq_write_func(false);
pon_msg();
update_488();
@@ -398,7 +429,7 @@ void phi_device::device_reset()
void phi_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
- LOG_0(("tmr %d enabled %d\n" , id , timer.enabled()));
+ LOG_NOISY("tmr %d enabled %d\n" , id , timer.enabled());
update_fsm();
}
@@ -409,7 +440,7 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
data = (data & REG_D08D15_MASK) | ((m_reg_status << (REG_D0D1_SHIFT - REG_STATUS_D0D1_BIT)) & REG_D0D1_MASK);
}
- //LOG(("W %u=%04x\n" , offset , data));
+ LOG_REG("W %u=%04x\n" , offset , data);
switch (offset) {
case REG_W_INT_COND:
@@ -447,6 +478,11 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
m_reg_control = data & 0xfe;
if (BIT(data , REG_CTRL_INIT_OFIFO_BIT)) {
m_fifo_out.clear();
+ if (m_c_state == PHI_C_CSBS) {
+ // Take control asynchronously
+ m_c_state = PHI_C_CSWS;
+ m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T7));
+ }
}
if (m_loopback) {
// TODO: better?
@@ -462,8 +498,7 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
bool prev_ol = BIT(m_reg_address , REG_ADDR_ONLINE_BIT);
m_reg_address = data;
bool current_ol = BIT(m_reg_address , REG_ADDR_ONLINE_BIT);
- // TODO: consider SYS CNTRL input, too
- m_sys_controller = !current_ol;
+ m_sys_controller = !current_ol || m_sys_cntrl_read_func();
m_loopback = !current_ol;
if (!current_ol) {
// IDENTIFY is enabled by PP_RESPONSE bit in control register
@@ -473,6 +508,7 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
pon_msg();
m_id_enabled = BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT);
}
+ configure_pp_response();
if (prev_ol != current_ol) {
update_488();
}
@@ -493,7 +529,7 @@ void phi_device::int_reg_w(offs_t offset , uint16_t data)
break;
default:
- LOG(("Writing to unmapped address (%u)\n", offset));
+ LOG("Writing to unmapped address (%u)\n", offset);
break;
}
}
@@ -510,7 +546,7 @@ uint8_t phi_device::get_dio(void)
void phi_device::set_dio(uint8_t data)
{
if (data != m_dio) {
- LOG_0(("DIO=%02x\n" , data));
+ LOG_NOISY("DIO=%02x\n" , data);
m_dio = data;
if (!m_loopback) {
m_dio_write_func(~data);
@@ -531,15 +567,15 @@ void phi_device::set_signal(phi_488_signal_t signal , bool state)
{
if (state != m_signals[ signal ]) {
m_signals[ signal ] = state;
- LOG_0(("INT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
- m_signals[ PHI_488_EOI ] ,
- m_signals[ PHI_488_DAV ] ,
- m_signals[ PHI_488_NRFD ] ,
- m_signals[ PHI_488_NDAC ] ,
- m_signals[ PHI_488_IFC ] ,
- m_signals[ PHI_488_SRQ ] ,
- m_signals[ PHI_488_ATN ] ,
- m_signals[ PHI_488_REN ]));
+ LOG_NOISY("INT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
+ m_signals[ PHI_488_EOI ] ,
+ m_signals[ PHI_488_DAV ] ,
+ m_signals[ PHI_488_NRFD ] ,
+ m_signals[ PHI_488_NDAC ] ,
+ m_signals[ PHI_488_IFC ] ,
+ m_signals[ PHI_488_SRQ ] ,
+ m_signals[ PHI_488_ATN ] ,
+ m_signals[ PHI_488_REN ]);
if (!m_loopback) {
m_signal_wr_fns[ signal ](!state);
}
@@ -554,18 +590,10 @@ void phi_device::pon_msg(void)
m_t_spms = false;
m_l_state = PHI_L_LIDS;
m_sr_state = PHI_SR_NPRS;
- m_pp_pacs = false;
- uint8_t addr = my_address();
- if (addr <= 7) {
- // If address <= 7, PP is automatically enabled and configured for PPR = ~address
- m_ppr_msg = addr ^ 7;
- m_pp_state = PHI_PP_PPSS;
- } else {
- m_ppr_msg = 0;
- m_pp_state = PHI_PP_PPIS;
- }
- m_s_sense = true;
+ m_rl_rems = false;
+ m_pp_state = PHI_PP_PPIS;
m_c_state = PHI_C_CIDS;
+ m_sa_state = PHI_SA_NONE;
m_be_counter = 0;
m_nba_origin = NBA_NONE;
}
@@ -597,26 +625,30 @@ void phi_device::update_fsm(void)
set_signal(PHI_488_IFC , m_sys_controller && BIT(m_reg_control , REG_CTRL_IFC_BIT));
set_signal(PHI_488_REN , m_sys_controller && BIT(m_reg_control , REG_CTRL_REN_BIT));
+ // TODO: improve (see SR FSM)
+ // This is not entirely correct but it works for now (on HP64K, the only system
+ // where it's relevant)
+ set_signal(PHI_488_SRQ , BIT(m_reg_control , REG_CTRL_SERVICE_REQ_BIT));
+
bool changed = true;
int prev_state;
uint8_t new_byte = 0;
bool new_eoi = false;
bool prev_cic = controller_in_charge();
// TODO: SR FSM
- // TODO: RL FSM
// Loop until all changes settle
while (changed) {
- LOG_0(("SH %d AH %d T %d SPMS %d L %d SR %d PP %d PACS %d PPR %u S %d C %d\n" ,
- m_sh_state , m_ah_state , m_t_state , m_t_spms , m_l_state , m_sr_state ,
- m_pp_state , m_pp_pacs , m_ppr_msg , m_s_sense , m_c_state));
- LOG_0(("O E/F=%d/%d I E/F=%d/%d\n" , m_fifo_out.empty() , m_fifo_out.full() , m_fifo_in.empty() , m_fifo_in.full()));
+ LOG_NOISY("SH %d AH %d T %d SPMS %d L %d SR %d PP %d PPR %u S %d C %d SA %d\n" ,
+ m_sh_state , m_ah_state , m_t_state , m_t_spms , m_l_state , m_sr_state ,
+ m_pp_state , m_ppr_msg , m_s_sense , m_c_state , m_sa_state);
+ LOG_NOISY("O E/F=%d/%d I E/F=%d/%d\n" , m_fifo_out.empty() , m_fifo_out.full() , m_fifo_in.empty() , m_fifo_in.full());
changed = false;
// SH FSM
prev_state = m_sh_state;
bool sh_reset =
(get_signal(PHI_488_ATN) && !(m_c_state == PHI_C_CACS || m_c_state == PHI_C_CTRS)) ||
- (!get_signal(PHI_488_ATN) && !(m_t_state == PHI_T_TACS || m_t_state == PHI_T_SPAS || m_t_state == PHI_T_ID3 || m_t_state == PHI_T_ID5));
+ (!get_signal(PHI_488_ATN) && !(m_t_state == PHI_T_TACS || m_t_state == PHI_T_SPAS || m_t_state == PHI_T_ID2 || m_t_state == PHI_T_ID4));
if (sh_reset) {
m_sh_state = PHI_SH_SIDS;
@@ -626,8 +658,8 @@ void phi_device::update_fsm(void)
case PHI_SH_SIDS:
if (m_t_state == PHI_T_TACS ||
m_t_state == PHI_T_SPAS ||
- m_t_state == PHI_T_ID3 ||
- m_t_state == PHI_T_ID5 ||
+ m_t_state == PHI_T_ID2 ||
+ m_t_state == PHI_T_ID4 ||
m_c_state == PHI_C_CACS) {
m_sh_state = PHI_SH_SGNS;
}
@@ -637,7 +669,7 @@ void phi_device::update_fsm(void)
if ((m_nba_origin = nba_msg(new_byte , new_eoi)) != NBA_NONE) {
m_sh_state = PHI_SH_SDYS;
m_sh_dly_timer->adjust(attotime::from_nsec(DELAY_T1));
- LOG_0(("SH DLY enabled %d\n" , m_sh_dly_timer->enabled()));
+ LOG_NOISY("SH DLY enabled %d\n" , m_sh_dly_timer->enabled());
}
break;
@@ -649,7 +681,7 @@ void phi_device::update_fsm(void)
case PHI_SH_STRS:
if (!get_signal(PHI_488_NDAC)) {
- LOG(("TX %02x/%d\n" , m_dio , m_signals[ PHI_488_EOI ]));
+ LOG("%.6f TX %02x/%d\n" , machine().time().as_double() , m_dio , m_signals[ PHI_488_EOI ]);
m_sh_state = PHI_SH_SGNS;
clear_nba((nba_origin_t)m_nba_origin);
}
@@ -779,33 +811,30 @@ void phi_device::update_fsm(void)
break;
case PHI_T_ID1:
- break;
-
- case PHI_T_ID2:
if (!get_signal(PHI_488_ATN)) {
- m_t_state = PHI_T_ID3;
+ m_t_state = PHI_T_ID2;
}
break;
- case PHI_T_ID3:
+ case PHI_T_ID2:
if (get_signal(PHI_488_ATN)) {
- m_t_state = PHI_T_ID2;
+ m_t_state = PHI_T_ID1;
}
break;
- case PHI_T_ID4:
+ case PHI_T_ID3:
if (!get_signal(PHI_488_ATN)) {
- m_t_state = PHI_T_ID5;
+ m_t_state = PHI_T_ID4;
}
break;
- case PHI_T_ID5:
+ case PHI_T_ID4:
if (get_signal(PHI_488_ATN)) {
- m_t_state = PHI_T_ID4;
+ m_t_state = PHI_T_ID3;
}
break;
- case PHI_T_ID6:
+ case PHI_T_ID5:
break;
default:
@@ -852,6 +881,13 @@ void phi_device::update_fsm(void)
}
// No direct L outputs
+ // RL FSM
+ if (!get_signal(PHI_488_REN) && m_rl_rems) {
+ m_rl_rems = false;
+ changed = true;
+ }
+ // No direct RL outputs
+
// PP FSM
prev_state = m_pp_state;
switch (m_pp_state) {
@@ -879,8 +915,8 @@ void phi_device::update_fsm(void)
}
// PP outputs
if (m_pp_state == PHI_PP_PPAS && m_s_sense == !!BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT)) {
- LOG(("PP %u\n" , m_ppr_msg));
- dio_byte |= (1U << m_ppr_msg);
+ LOG("%.6f PP %u\n" , machine().time().as_double() , m_ppr_msg);
+ dio_byte |= BIT_MASK<uint8_t>(m_ppr_msg);
}
// C FSM
@@ -918,19 +954,17 @@ void phi_device::update_fsm(void)
m_be_counter = 0;
} else if (rpp_msg()) {
// Start parallel polling
- m_c_state = PHI_C_CPWS;
+ m_c_state = PHI_C_CPPS;
}
- // It's not clear what PHI does when it's controller-in-charge
- // and it's nothing to do. Here we park it in CACS.
+ // There's no third case: rpp_msg() is true when m_fifo_out.empty() is true
}
break;
- case PHI_C_CPWS:
- // TODO:
- break;
-
case PHI_C_CPPS:
- // TODO:
+ if (!rpp_msg()) {
+ m_c_state = PHI_C_CAWS;
+ m_c_dly_timer->adjust(attotime::from_nsec(DELAY_T9));
+ }
break;
case PHI_C_CSBS:
@@ -950,7 +984,7 @@ void phi_device::update_fsm(void)
case PHI_C_CAWS:
if (rpp_msg()) {
- m_c_state = PHI_C_CPWS;
+ m_c_state = PHI_C_CPPS;
m_c_dly_timer->reset();
} else if (!m_c_dly_timer->enabled()) {
m_c_state = PHI_C_CACS;
@@ -979,10 +1013,10 @@ void phi_device::update_fsm(void)
changed = true;
}
// C outputs
- set_signal(PHI_488_ATN , m_c_state == PHI_C_CACS || m_c_state == PHI_C_CPWS ||
+ set_signal(PHI_488_ATN , m_c_state == PHI_C_CACS ||
m_c_state == PHI_C_CPPS || m_c_state == PHI_C_CSWS ||
m_c_state == PHI_C_CAWS || m_c_state == PHI_C_CTRS);
- eoi_signal = eoi_signal || m_c_state == PHI_C_CPWS || m_c_state == PHI_C_CPPS;
+ eoi_signal = eoi_signal || m_c_state == PHI_C_CPPS;
set_signal(PHI_488_EOI , eoi_signal);
set_dio(dio_byte);
}
@@ -992,7 +1026,7 @@ void phi_device::update_fsm(void)
if (m_l_state != PHI_L_LIDS) {
BIT_SET(m_reg_status, REG_STATUS_LISTEN_BIT);
}
- if (m_t_state != PHI_T_TIDS && m_t_state != PHI_T_ID1) {
+ if (m_t_state != PHI_T_TIDS) {
BIT_SET(m_reg_status, REG_STATUS_TALK_BIT);
}
if (m_sys_controller) {
@@ -1001,7 +1035,9 @@ void phi_device::update_fsm(void)
if (controller_in_charge()) {
BIT_SET(m_reg_status, REG_STATUS_CONTROLLER_BIT);
}
- // TODO: REG_STATUS_REMOTE_BIT
+ if (m_rl_rems) {
+ BIT_SET(m_reg_status, REG_STATUS_REMOTE_BIT);
+ }
// Update interrupting condition register and INT signal
if (prev_cic != controller_in_charge()) {
@@ -1020,28 +1056,16 @@ void phi_device::update_fsm(void)
if (controller_in_charge() && get_signal(PHI_488_SRQ)) {
BIT_SET(m_reg_int_cond, REG_INT_SRQ_BIT);
}
- // TODO: REG_INT_PP_RESPONSE_BIT
- bool int_pending = (m_reg_int_cond & m_reg_int_mask) != 0;
- bool int_line = false;
- if (int_pending) {
- BIT_SET(m_reg_int_cond, REG_INT_PENDING_BIT);
- if (BIT(m_reg_int_mask , REG_INT_PENDING_BIT)) {
- int_line = true;
- }
- }
- if (int_line != m_int_line) {
- m_int_line = int_line;
- m_int_write_func(m_int_line);
- }
+ update_pp();
+ update_interrupt();
+ update_dmarq();
- (void)m_dmarq_line; // TODO: update DMARQ
m_no_recursion = false;
}
phi_device::nba_origin_t phi_device::nba_msg(uint8_t& new_byte , bool& new_eoi) const
{
- // TODO: consider CIC
- if (!m_fifo_out.empty()) {
+ if (controller_in_charge() && m_c_state == PHI_C_CACS && !m_fifo_out.empty()) {
uint16_t word = m_fifo_out.peek();
if ((word & REG_D0D1_MASK) == REG_OFIFO_IFCMD_MASK) {
// Controller sends an interface command
@@ -1071,21 +1095,22 @@ phi_device::nba_origin_t phi_device::nba_msg(uint8_t& new_byte , bool& new_eoi)
case PHI_T_SPAS:
// Reply to serial poll: STB & RQS
+ // TODO: check
new_byte = m_sr_state == PHI_SR_NPRS ? 0x80 : 0x40;
new_eoi = false;
return NBA_FROM_SPAS;
- case PHI_T_ID3:
+ case PHI_T_ID2:
// 1st byte of ID
new_byte = (uint8_t)m_reg_1st_id;
new_eoi = false;
- return NBA_FROM_ID3;
+ return NBA_FROM_ID2;
- case PHI_T_ID5:
+ case PHI_T_ID4:
// 2nd byte of ID
new_byte = (uint8_t)m_reg_2nd_id;
new_eoi = true;
- return NBA_FROM_ID5;
+ return NBA_FROM_ID4;
default:
break;
@@ -1101,12 +1126,12 @@ void phi_device::clear_nba(nba_origin_t origin)
m_fifo_out.dequeue();
break;
- case NBA_FROM_ID3:
- m_t_state = PHI_T_ID4;
+ case NBA_FROM_ID2:
+ m_t_state = PHI_T_ID3;
break;
- case NBA_FROM_ID5:
- m_t_state = PHI_T_ID6;
+ case NBA_FROM_ID4:
+ m_t_state = PHI_T_ID5;
break;
default:
@@ -1116,20 +1141,23 @@ void phi_device::clear_nba(nba_origin_t origin)
bool phi_device::if_cmd_received(uint8_t byte)
{
- LOG(("RX cmd: %02x\n" , byte));
+ LOG("%.6f RX cmd: %02x\n" , machine().time().as_double() , byte);
bool accepted = true;
- if ((byte & IFCMD_AG_MASK) != IFCMD_SCG_VALUE && byte != IFCMD_PPC) {
- // PACS -> PUCS when receiving a PCG command that is not PPC
- m_pp_pacs = false;
+ if ((byte & IFCMD_AG_MASK) != IFCMD_SCG_VALUE) {
+ // Any PCG clears sec. address recognition
+ // Exceptions are intercepted below
+ m_sa_state = PHI_SA_NONE;
}
// TODO: IFC & non-reflection into controller
switch (byte) {
case IFCMD_GTL:
// Go to local
- // TODO:
+ if (m_l_state == PHI_L_LADS) {
+ m_rl_rems = false;
+ }
break;
case IFCMD_SDC:
@@ -1142,7 +1170,7 @@ bool phi_device::if_cmd_received(uint8_t byte)
case IFCMD_PPC:
// Parallel poll configure
if (m_l_state == PHI_L_LADS) {
- m_pp_pacs = true;
+ m_sa_state = PHI_SA_PACS;
}
break;
@@ -1165,7 +1193,7 @@ bool phi_device::if_cmd_received(uint8_t byte)
case IFCMD_LLO:
// Local lock-out
- // TODO:
+ // Ignored
break;
case IFCMD_DCL:
@@ -1194,19 +1222,20 @@ bool phi_device::if_cmd_received(uint8_t byte)
case IFCMD_UNL:
// Unlisten
- if (m_l_state == PHI_L_LADS && !lon_msg()) {
+ if (!lon_msg()) {
m_l_state = PHI_L_LIDS;
}
break;
case IFCMD_UNT:
// Untalk
- if (!ton_msg()) {
- if (m_id_enabled) {
- m_t_state = PHI_T_ID1;
- } else {
- m_t_state = PHI_T_TIDS;
- }
+ if (ton_msg()) {
+ m_t_state = PHI_T_TADS;
+ } else {
+ m_t_state = PHI_T_TIDS;
+ }
+ if (m_id_enabled) {
+ m_sa_state = PHI_SA_UNT;
}
break;
@@ -1218,51 +1247,65 @@ bool phi_device::if_cmd_received(uint8_t byte)
if (ag == IFCMD_LAG_VALUE) {
// LAG
- if (!lon_msg() && m_l_state == PHI_L_LIDS && my_addr) {
+ if (my_addr) {
+ // MLA
m_l_state = PHI_L_LADS;
+ if (get_signal(PHI_488_REN)) {
+ m_rl_rems = true;
+ }
+ m_sa_state = PHI_SA_LPAS;
}
} else if (ag == IFCMD_TAG_VALUE) {
// TAG
- if (!ton_msg()) {
- if (my_addr) {
- // MTA
- m_t_state = PHI_T_TADS;
- } else {
- // OTA
- m_t_state = PHI_T_TIDS;
- }
+ if (my_addr) {
+ // MTA
+ m_t_state = PHI_T_TADS;
+ m_sa_state = PHI_SA_TPAS;
+ } else if (!ton_msg()) {
+ // OTA
+ m_t_state = PHI_T_TIDS;
}
} else if (ag == IFCMD_SCG_VALUE) {
// SCG
- if (m_pp_pacs) {
+ switch (m_sa_state) {
+ case PHI_SA_NONE:
+ break;
+
+ case PHI_SA_PACS:
if ((byte & IFCMD_PPX_MASK) == IFCMD_PPE_VALUE && m_pp_state == PHI_PP_PPIS) {
// PPE
m_s_sense = BIT(byte , IFCMD_PPE_S_BIT);
m_ppr_msg = byte & IFCMD_PPE_PPR_MASK;
+ LOG("PPE s=%d ppr=%u\n" , m_s_sense , m_ppr_msg);
m_pp_state = PHI_PP_PPSS;
} else if ((byte & IFCMD_PPX_MASK) == IFCMD_PPD_VALUE && m_pp_state == PHI_PP_PPSS) {
// PPD
m_pp_state = PHI_PP_PPIS;
}
- } else {
- // command is a secondary address
- if (m_t_state == PHI_T_ID1 && (m_l_state == PHI_L_LADS) == !!lon_msg() && my_addr) {
+ break;
+
+ case PHI_SA_TPAS:
+ case PHI_SA_LPAS:
+ // command is a secondary address after MTA or MLA
+ if (m_fifo_in.full() || BIT(m_reg_int_cond , REG_INT_DEV_CLEAR_BIT)) {
+ // No room for secondary address in FIFO, stall handshake
+ accepted = false;
+ } else {
+ uint16_t word = REG_IFIFO_2_ADDR_MASK | address;
+ if (m_sa_state == PHI_SA_TPAS) {
+ BIT_SET(word, REG_IFIFO_TALK_BIT);
+ }
+ rx_n_data_freeze(word);
+ }
+ break;
+
+ case PHI_SA_UNT:
+ if (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) {
- // Unaddressed by OSA
m_t_state = PHI_T_ID1;
- } else if (m_t_state == PHI_T_TADS || m_l_state == PHI_L_LADS) {
- if (m_fifo_in.full() || BIT(m_reg_int_cond , REG_INT_DEV_CLEAR_BIT)) {
- // No room for secondary address in FIFO, stall handshake
- accepted = false;
- } else {
- uint16_t word = REG_IFIFO_2_ADDR_MASK | address;
- if (m_t_state == PHI_T_TADS) {
- BIT_SET(word, REG_IFIFO_TALK_BIT);
- }
- rx_n_data_freeze(word);
- }
+ } else {
+ // Unaddressed by OSA (== UNT)
+ if_cmd_received(IFCMD_UNT);
}
}
}
@@ -1299,20 +1342,20 @@ bool phi_device::byte_received(uint8_t byte , bool eoi)
}
}
- LOG(("RX word:%04x\n" , word));
+ LOG("%.6f RX word:%04x\n" , machine().time().as_double() , word);
if (m_l_state == PHI_L_LACS) {
if (m_fifo_in.full() || BIT(m_reg_int_cond , REG_INT_DEV_CLEAR_BIT)) {
// No room for received byte, stall handshake
- LOG_0(("..stalled\n"));
+ LOG_NOISY("..stalled\n");
return false;
} else {
- LOG_0(("..OK\n"));
+ LOG_NOISY("..OK\n");
rx_n_data_freeze(word);
}
}
if (end_of_transfer) {
- LOG_0(("End of byte transfer enable\n"));
+ LOG_NOISY("End of byte transfer enable\n");
m_fifo_out.dequeue();
m_be_counter = 0;
} else {
@@ -1325,7 +1368,7 @@ bool phi_device::byte_received(uint8_t byte , bool eoi)
void phi_device::rx_n_data_freeze(uint16_t word)
{
m_fifo_in.enqueue(word);
- if (m_sh_state != PHI_SH_STRS) {
+ if (!controller_in_charge() && m_sh_state != PHI_SH_STRS) {
// If PHI didn't send this byte to itself, set data freeze
BIT_SET(m_reg_status, REG_STATUS_DATA_FREEZE_BIT);
}
@@ -1364,22 +1407,84 @@ bool phi_device::tcs_msg(void) const
bool new_eoi;
// When the CIC takes back control synchronously:
- // * Nothing in OFIFO
- // * Request to start parallel poll is pending
+ // * Request to start parallel poll is pending (i.e. OFIFO is empty)
// * There's an interface command to be sent at head of OFIFO
return (m_c_state == PHI_C_CSBS || m_c_state == PHI_C_CSHS || m_c_state == PHI_C_CSWS) &&
- (m_fifo_out.empty() ||
- rpp_msg() ||
+ (rpp_msg() ||
nba_msg(new_byte , new_eoi) == NBA_CMD_FROM_OFIFO);
}
bool phi_device::rpp_msg(void) const
{
- // TODO:
- return false;
+ return m_fifo_out.empty();
+}
+
+uint8_t phi_device::get_pp_response()
+{
+ return (get_dio() ^ m_reg_2nd_id) & m_reg_1st_id;
}
bool phi_device::controller_in_charge(void) const
{
return m_c_state != PHI_C_CIDS;
}
+
+void phi_device::configure_pp_response()
+{
+ uint8_t addr = (m_reg_address >> REG_ADDR_HPIB_ADDR_BIT) & 0x1f;
+ if (addr <= 7) {
+ // If address <= 7, PP is automatically enabled and configured for PPR = ~address
+ m_ppr_msg = addr ^ 7;
+ m_pp_state = PHI_PP_PPSS;
+ } else {
+ m_ppr_msg = 0;
+ m_pp_state = PHI_PP_PPIS;
+ }
+ m_s_sense = true;
+}
+
+void phi_device::update_pp()
+{
+ if (m_c_state == PHI_C_CPPS) {
+ if (m_fifo_in.empty() && get_pp_response()) {
+ BIT_SET(m_reg_int_cond , REG_INT_PP_RESPONSE_BIT);
+ } else {
+ BIT_CLR(m_reg_int_cond , REG_INT_PP_RESPONSE_BIT);
+ }
+ update_interrupt();
+ }
+}
+
+void phi_device::update_interrupt()
+{
+ bool int_pending = (m_reg_int_cond & m_reg_int_mask) != 0;
+ bool int_line = false;
+ if (int_pending) {
+ BIT_SET(m_reg_int_cond, REG_INT_PENDING_BIT);
+ if (BIT(m_reg_int_mask , REG_INT_PENDING_BIT)) {
+ int_line = true;
+ }
+ } else {
+ BIT_CLR(m_reg_int_cond, REG_INT_PENDING_BIT);
+ }
+ if (int_line != m_int_line) {
+ m_int_line = int_line;
+ LOG_INT("INT %d\n" , m_int_line);
+ m_int_write_func(m_int_line);
+ }
+}
+
+void phi_device::update_dmarq()
+{
+ bool new_dmarq_line;
+ if (BIT(m_reg_control , REG_CTRL_DMA_FIFO_BIT)) {
+ new_dmarq_line = BIT(m_reg_int_cond , REG_INT_FIFO_ROOM_BIT);
+ } else {
+ new_dmarq_line = BIT(m_reg_int_cond , REG_INT_FIFO_AV_BIT);
+ }
+ if (new_dmarq_line != m_dmarq_line) {
+ m_dmarq_line = new_dmarq_line;
+ LOG_INT("DRQ %d\n" , m_dmarq_line);
+ m_dmarq_write_func(m_dmarq_line);
+ }
+}
diff --git a/src/devices/machine/phi.h b/src/devices/machine/phi.h
index 6a1e9bfaad5..59b538e8fc8 100644
--- a/src/devices/machine/phi.h
+++ b/src/devices/machine/phi.h
@@ -49,6 +49,10 @@
#define MCFG_PHI_DMARQ_WRITE_CB(_write) \
downcast<phi_device &>(*device).set_dmarq_write_cb(DEVCB_##_write);
+// Set read callback for SYS_CNTRL signal
+#define MCFG_PHI_SYS_CNTRL_READ_CB(_read) \
+ downcast<phi_device &>(*device).set_sys_cntrl_read_cb(DEVCB_##_read);
+
class phi_device : public device_t
{
public:
@@ -68,11 +72,23 @@ public:
PHI_488_SIGNAL_COUNT
};
- template<class Object> devcb_base& set_dio_read_cb(Object &&cb) { return m_dio_read_func.set_callback(std::forward<Object>(cb)); }
- template<class Object> devcb_base& set_dio_write_cb(Object &&cb) { return m_dio_write_func.set_callback(std::forward<Object>(cb)); }
- template<class Object> devcb_base& set_488_signal_write_cb(phi_488_signal_t signal , Object &&cb) { return m_signal_wr_fns[ signal ].set_callback(std::forward<Object>(cb)); }
- template<class Object> devcb_base& set_int_write_cb(Object &&cb) { return m_int_write_func.set_callback(std::forward<Object>(cb)); }
- template<class Object> devcb_base& set_dmarq_write_cb(Object &&cb) { return m_dmarq_write_func.set_callback(std::forward<Object>(cb)); }
+ template <class Object> devcb_base& set_dio_read_cb(Object &&cb)
+ { return m_dio_read_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_dio_write_cb(Object &&cb)
+ { return m_dio_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_488_signal_write_cb(phi_488_signal_t signal , Object &&cb)
+ { return m_signal_wr_fns[ signal ].set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_int_write_cb(Object &&cb)
+ { return m_int_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base& set_dmarq_write_cb(Object &&cb)
+ { return m_dmarq_write_func.set_callback(std::forward<Object>(cb)); }
+
+ template <class Object> devcb_base &set_sys_cntrl_read_cb(Object &&cb)
+ { return m_sys_cntrl_read_func.set_callback(std::forward<Object>(cb)); }
DECLARE_WRITE_LINE_MEMBER(eoi_w);
DECLARE_WRITE_LINE_MEMBER(dav_w);
@@ -83,6 +99,8 @@ public:
DECLARE_WRITE_LINE_MEMBER(atn_w);
DECLARE_WRITE_LINE_MEMBER(ren_w);
+ DECLARE_WRITE8_MEMBER(bus_dio_w);
+
void set_ext_signal(phi_488_signal_t signal , int state);
// Register read/write
@@ -127,7 +145,7 @@ private:
devcb_write_line m_signal_wr_fns[ PHI_488_SIGNAL_COUNT ];
devcb_write_line m_int_write_func;
devcb_write_line m_dmarq_write_func;
-
+ devcb_read_line m_sys_cntrl_read_func;
bool m_int_line;
bool m_dmarq_line;
@@ -172,12 +190,11 @@ private:
PHI_T_SPAS,
PHI_T_TACS,
// The following are non-standard states for IDENTIFY sequencing
- PHI_T_ID1, // Untalked
- PHI_T_ID2, // Addressed by secondary address
- PHI_T_ID3, // Sending 1st byte
- PHI_T_ID4, // Waiting to send 2nd byte
- PHI_T_ID5, // Sending 2nd byte
- PHI_T_ID6 // 2nd byte sent, end of sequence
+ PHI_T_ID1, // Addressed by secondary address
+ PHI_T_ID2, // Sending 1st byte
+ PHI_T_ID3, // Waiting to send 2nd byte
+ PHI_T_ID4, // Sending 2nd byte
+ PHI_T_ID5 // 2nd byte sent, end of sequence
};
int m_t_state;
@@ -201,6 +218,9 @@ private:
int m_sr_state;
+ // RL (Remote Local) states
+ bool m_rl_rems; // false: LOCS, true: REMS
+
// PP (Parallel poll) states
enum {
PHI_PP_PPIS,
@@ -209,7 +229,6 @@ private:
};
int m_pp_state;
- bool m_pp_pacs;
uint8_t m_ppr_msg;
bool m_s_sense;
@@ -218,7 +237,6 @@ private:
PHI_C_CIDS,
PHI_C_CADS,
PHI_C_CACS,
- PHI_C_CPWS,
PHI_C_CPPS,
PHI_C_CSBS,
PHI_C_CSHS,
@@ -228,6 +246,18 @@ private:
};
int m_c_state;
+
+ // Secondary address decoder states
+ enum {
+ PHI_SA_NONE,
+ PHI_SA_PACS,
+ PHI_SA_TPAS,
+ PHI_SA_LPAS,
+ PHI_SA_UNT
+ };
+
+ int m_sa_state;
+
uint8_t m_be_counter;
uint16_t m_reg_status;
uint16_t m_reg_int_cond;
@@ -244,8 +274,8 @@ private:
NBA_CMD_FROM_OFIFO,
NBA_BYTE_FROM_OFIFO,
NBA_FROM_SPAS,
- NBA_FROM_ID3,
- NBA_FROM_ID5
+ NBA_FROM_ID2,
+ NBA_FROM_ID4
} nba_origin_t;
int m_nba_origin;
@@ -275,7 +305,12 @@ private:
uint8_t my_address(void) const;
bool tcs_msg(void) const;
bool rpp_msg(void) const;
+ uint8_t get_pp_response();
bool controller_in_charge(void) const;
+ void configure_pp_response();
+ void update_pp();
+ void update_interrupt();
+ void update_dmarq();
};
// device type definition
diff --git a/src/mame/drivers/hp64k.cpp b/src/mame/drivers/hp64k.cpp
index 886a2f05d39..023f4d14f47 100644
--- a/src/mame/drivers/hp64k.cpp
+++ b/src/mame/drivers/hp64k.cpp
@@ -59,7 +59,7 @@
// exponentially decaying envelope (a bell sound) whereas in the emulation it's inside a
// simple rectangular envelope.
//
-//*U20 HP "PHI" Custom HP-IB interface microcontroller
+// U20 HP "PHI" Custom HP-IB interface microcontroller
// U28 i8251 RS232 UART
//
// **********
@@ -145,9 +145,6 @@
// 1 Enable drive 0 motor (0)
// 0 Enable drive 0 (0)
//
-//
-// ICs that are not emulated yet are marked with "*"
-//
#include "emu.h"
#include "bus/rs232/rs232.h"
@@ -162,6 +159,8 @@
#include "video/i8275.h"
#include "screen.h"
#include "speaker.h"
+#include "machine/phi.h"
+#include "bus/ieee488/ieee488.h"
#define BIT_MASK(n) (1U << (n))
@@ -228,6 +227,11 @@ public:
DECLARE_WRITE_LINE_MEMBER(hp64k_rs232_dcd_w);
DECLARE_WRITE_LINE_MEMBER(hp64k_rs232_cts_w);
+ DECLARE_READ16_MEMBER(hp64k_phi_r);
+ DECLARE_WRITE16_MEMBER(hp64k_phi_w);
+ DECLARE_WRITE_LINE_MEMBER(hp64k_phi_int_w);
+ DECLARE_READ_LINE_MEMBER(hp64k_phi_sys_ctrl_r);
+
DECLARE_WRITE16_MEMBER(hp64k_beep_w);
TIMER_DEVICE_CALLBACK_MEMBER(hp64k_beeper_off);
@@ -256,6 +260,7 @@ private:
required_ioport m_s5_sw;
required_device<i8251_device> m_uart;
required_device<rs232_port_device> m_rs232;
+ required_device<phi_device> m_phi;
// Character generator
const uint8_t *m_chargen;
@@ -314,6 +319,9 @@ private:
bool m_txd_state;
bool m_dtr_state;
bool m_rts_state;
+
+ // HPIB I/F
+ uint8_t m_phi_reg;
};
ADDRESS_MAP_START(hp64k_state::cpu_mem_map)
@@ -339,6 +347,9 @@ ADDRESS_MAP_START(hp64k_state::cpu_io_map)
// PA = 6, IC = [0..3]
// Read from USART
AM_RANGE(HP_MAKE_IOADDR(6 , 0) , HP_MAKE_IOADDR(6 , 3)) AM_READ(hp64k_usart_r)
+ // PA = 7, IC = 1
+ // PHI
+ AM_RANGE(HP_MAKE_IOADDR(7 , 1) , HP_MAKE_IOADDR(7 , 1)) AM_READWRITE(hp64k_phi_r , hp64k_phi_w)
// PA = 7, IC = 2
// Rear-panel switches and loopback relay control
AM_RANGE(HP_MAKE_IOADDR(7 , 2) , HP_MAKE_IOADDR(7 , 2)) AM_READWRITE(hp64k_rear_sw_r , hp64k_loopback_w)
@@ -374,7 +385,8 @@ hp64k_state::hp64k_state(const machine_config &mconfig, device_type type, const
m_baud_rate(*this , "baud_rate"),
m_s5_sw(*this , "s5_sw"),
m_uart(*this , "uart"),
- m_rs232(*this , "rs232")
+ m_rs232(*this , "rs232"),
+ m_phi(*this , "phi")
{
}
@@ -418,7 +430,7 @@ void hp64k_state::machine_reset()
m_txd_state = true;
m_dtr_state = true;
m_rts_state = true;
-
+ m_phi_reg = 0;
}
uint8_t hp64k_state::hp64k_crtc_filter(uint8_t data)
@@ -1027,6 +1039,7 @@ WRITE_LINE_MEMBER(hp64k_state::hp64k_rts_w)
WRITE16_MEMBER(hp64k_state::hp64k_loopback_w)
{
+ m_phi_reg = (uint8_t)((data >> 8) & 7);
m_loopback = BIT(data , 11);
hp64k_update_loopback();
}
@@ -1058,6 +1071,16 @@ WRITE_LINE_MEMBER(hp64k_state::hp64k_rs232_dcd_w)
}
}
+READ16_MEMBER(hp64k_state::hp64k_phi_r)
+{
+ return m_phi->reg16_r(space , m_phi_reg , mem_mask);
+}
+
+WRITE16_MEMBER(hp64k_state::hp64k_phi_w)
+{
+ m_phi->reg16_w(space , m_phi_reg , data , mem_mask);
+}
+
WRITE_LINE_MEMBER(hp64k_state::hp64k_rs232_cts_w)
{
if (!m_loopback) {
@@ -1065,6 +1088,22 @@ WRITE_LINE_MEMBER(hp64k_state::hp64k_rs232_cts_w)
}
}
+WRITE_LINE_MEMBER(hp64k_state::hp64k_phi_int_w)
+{
+ if (state) {
+ BIT_SET(m_irl_pending , 7);
+ } else {
+ BIT_CLR(m_irl_pending , 7);
+ }
+
+ hp64k_update_irl();
+}
+
+READ_LINE_MEMBER(hp64k_state::hp64k_phi_sys_ctrl_r)
+{
+ return BIT(m_rear_panel_sw->read() , 6);
+}
+
WRITE16_MEMBER(hp64k_state::hp64k_beep_w)
{
if (!BIT(offset , 0)) {
@@ -1254,6 +1293,9 @@ static INPUT_PORTS_START(hp64k)
PORT_DIPNAME(0x0400 , 0x0400 , "E9-1 jumper")
PORT_DIPSETTING(0x0000 , DEF_STR(Yes))
PORT_DIPSETTING(0x0400 , DEF_STR(No))
+ PORT_DIPNAME(0x0040 , 0x0000 , "System controller")
+ PORT_DIPSETTING(0x0000 , DEF_STR(No))
+ PORT_DIPSETTING(0x0040 , DEF_STR(Yes))
PORT_DIPNAME(0x0018 , 0x0000 , "System source")
PORT_DIPLOCATION("S1:!7,!6")
PORT_DIPSETTING(0x0000 , "Sys bus")
@@ -1410,6 +1452,30 @@ MACHINE_CONFIG_START(hp64k_state::hp64k)
MCFG_RS232_DCD_HANDLER(WRITELINE(hp64k_state , hp64k_rs232_dcd_w))
MCFG_RS232_CTS_HANDLER(WRITELINE(hp64k_state , hp64k_rs232_cts_w))
+ MCFG_DEVICE_ADD("phi" , PHI , 0)
+ MCFG_PHI_INT_WRITE_CB(WRITELINE(hp64k_state , hp64k_phi_int_w))
+ MCFG_PHI_DMARQ_WRITE_CB(DEVWRITELINE("cpu" , hp_5061_3011_cpu_device , halt_w))
+ MCFG_PHI_SYS_CNTRL_READ_CB(READLINE(hp64k_state , hp64k_phi_sys_ctrl_r))
+ MCFG_PHI_DIO_READWRITE_CB(DEVREAD8(IEEE488_TAG , ieee488_device , dio_r) , DEVWRITE8(IEEE488_TAG , ieee488_device , dio_w))
+ MCFG_PHI_EOI_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , eoi_w))
+ MCFG_PHI_DAV_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , dav_w))
+ MCFG_PHI_NRFD_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , nrfd_w))
+ MCFG_PHI_NDAC_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , ndac_w))
+ MCFG_PHI_IFC_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , ifc_w))
+ MCFG_PHI_SRQ_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , srq_w))
+ MCFG_PHI_ATN_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , atn_w))
+ MCFG_PHI_REN_WRITE_CB(DEVWRITELINE(IEEE488_TAG , ieee488_device , ren_w))
+ MCFG_IEEE488_BUS_ADD()
+ MCFG_IEEE488_EOI_CALLBACK(DEVWRITELINE("phi" , phi_device , eoi_w))
+ MCFG_IEEE488_DAV_CALLBACK(DEVWRITELINE("phi" , phi_device , dav_w))
+ MCFG_IEEE488_NRFD_CALLBACK(DEVWRITELINE("phi" , phi_device , nrfd_w))
+ MCFG_IEEE488_NDAC_CALLBACK(DEVWRITELINE("phi" , phi_device , ndac_w))
+ MCFG_IEEE488_IFC_CALLBACK(DEVWRITELINE("phi" , phi_device , ifc_w))
+ MCFG_IEEE488_SRQ_CALLBACK(DEVWRITELINE("phi" , phi_device , srq_w))
+ MCFG_IEEE488_ATN_CALLBACK(DEVWRITELINE("phi" , phi_device , atn_w))
+ MCFG_IEEE488_REN_CALLBACK(DEVWRITELINE("phi" , phi_device , ren_w))
+ MCFG_IEEE488_DIO_CALLBACK(DEVWRITE8("phi" , phi_device , bus_dio_w))
+ // Feel so lonely here... waiting for the 488 remotizer ;)
MACHINE_CONFIG_END
ROM_START(hp64k)