hp64k: added support for HPIB bus. Extensive improvement of PHI emulation.

This commit is contained in:
fulivi 2018-03-11 17:22:24 +01:00
parent 81a35fb46e
commit 01e86e4cec
6 changed files with 498 additions and 266 deletions

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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
// 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))
// 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);
}
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;
}
break;
case PHI_T_ID3:
if (get_signal(PHI_488_ATN)) {
m_t_state = PHI_T_ID2;
}
break;
case PHI_T_ID4:
if (!get_signal(PHI_488_ATN)) {
m_t_state = PHI_T_ID5;
case PHI_T_ID2:
if (get_signal(PHI_488_ATN)) {
m_t_state = PHI_T_ID1;
}
break;
case PHI_T_ID5:
if (get_signal(PHI_488_ATN)) {
case PHI_T_ID3:
if (!get_signal(PHI_488_ATN)) {
m_t_state = PHI_T_ID4;
}
break;
case PHI_T_ID6:
case PHI_T_ID4:
if (get_signal(PHI_488_ATN)) {
m_t_state = PHI_T_ID3;
}
break;
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) {
// 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);
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_ID1;
} 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);
}
}

View File

@ -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

View File

@ -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)