HP HIL: passthrough commands between devices

The old code didn't loopback commands that are sent to a
non-existing HIL address. Unfortunately the HP 9000/300 Boot
ROM does that: it send a IDD command to every possible address
and fails if it's not looped back.

This also changes the API. HIL devices are now able to return true
if the command should be passed on to the next devices, or false
it it shouldn't. This is required for initial configuration of the Bus
and various other commands like POLL, which are sent to the global
address.

Signed-off-by: Sven Schnelle <svens@stackframe.org>
This commit is contained in:
Sven Schnelle 2017-09-03 21:12:12 +02:00
parent 49a7303d0f
commit 2d993a7b5d
4 changed files with 62 additions and 42 deletions

View File

@ -4,7 +4,7 @@
#include "machine/keyboard.ipp"
#define LOG 0
/***************************************************************************
DEVICE TYPE GLOBALS
***************************************************************************/
@ -276,13 +276,25 @@ void hle_device_base::device_reset()
start_processing(attotime::from_hz(1'200));
}
void hle_device_base::hil_write(uint16_t data)
// '
bool hle_device_base::hil_write(uint16_t *pdata)
{
int frames = 0;
// printf("rx from mlc %04X (%s %02X)\n", data, BIT(data, 11) ? "command" : "data", data & 255);
uint8_t addr = (*pdata >> 8) & 7;
uint8_t data = *pdata & 0xff;
bool command = BIT(*pdata, 11);
if (BIT(data, 11)) switch (data & 255)
if (LOG) {
logerror("rx from mlc %04X (%s addr %d, data %02X)\n", *pdata, \
command ? "command" : "data", addr, data);
}
if (!command)
goto out;
if (addr != 0 && addr != m_device_id)
goto out;
switch (data)
{
case HPHIL_IFC:
m_powerup = false;
@ -296,27 +308,35 @@ void hle_device_base::hil_write(uint16_t data)
m_passthru = false;
break;
case HPHIL_ACF+1:
m_device_id = data & 7;
m_device_id16 = m_device_id << 8;
m_hp_hil_mlc->hil_write((data & ~7) | ((data + 1) & 7));
return;
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
m_device_id = data - 8;
m_device_id16 = (data - 8) << 8;
*pdata &= ~7;
*pdata += (data - 7);
break;
case HPHIL_POL:
if (!m_fifo.empty())
{
m_hp_hil_mlc->hil_write(m_device_id16 | 0x40); // Keycode Set 1, no coordinate data
frames = 1;
m_hp_hil_mlc->hil_write(m_device_id16 | 0x40); // Keycode Set 1, no coordinate data
while (!m_fifo.empty())
{
m_hp_hil_mlc->hil_write(m_device_id16 | m_fifo.dequeue());
frames++;
}
}
m_hp_hil_mlc->hil_write(HPMLC_W1_C | m_device_id16 | HPHIL_POL | ((data + frames) & 7));
return;
break;
m_hp_hil_mlc->hil_write(HPMLC_W1_C | (addr << 8) | HPHIL_POL | (frames));
*pdata &= ~7;
*pdata += frames;
return true;
case HPHIL_DSR:
m_device_id = m_device_id16 = 0;
@ -324,30 +344,33 @@ void hle_device_base::hil_write(uint16_t data)
break;
case HPHIL_IDD:
m_hp_hil_mlc->hil_write(m_device_id16 | ioport("COL0")->read());
logerror("IDD\n");
m_hp_hil_mlc->hil_write(0x01cf);
m_hp_hil_mlc->hil_write(m_device_id16 | 0);
break;
case HPHIL_DHR:
m_powerup = true;
m_passthru = false;
device_reset();
return;
return true;
break;
default:
logerror("command %02X unknown\n", data & 255);
logerror("command %02X unknown\n", data);
break;
}
if (!m_passthru)
m_hp_hil_mlc->hil_write(data);
// else
// m_next->hil_write(data);
out:
if (!m_passthru) {
m_hp_hil_mlc->hil_write(*pdata);
return false;
}
return true;
}
void hle_device_base::transmit_byte(uint8_t byte)
{
if (!m_fifo.full()) {
// printf("queuing %02X\n", byte);
m_fifo.enqueue(byte);
}
// else

View File

@ -34,7 +34,7 @@ protected:
virtual void key_break(uint8_t row, uint8_t column) override;
// device_hp_hil_interface overrides
virtual void hil_write(uint16_t data) override;
virtual bool hil_write(uint16_t *data) override;
private:
void transmit_byte(uint8_t byte);

View File

@ -78,6 +78,7 @@ hp_hil_mlc_device::hp_hil_mlc_device(const machine_config &mconfig, const char *
, int_cb(*this)
, nmi_cb(*this)
{
m_loop = 1;
}
void hp_hil_mlc_device::add_hp_hil_device( device_hp_hil_interface *device )
@ -112,13 +113,16 @@ void hp_hil_mlc_device::device_reset()
WRITE8_MEMBER(hp_hil_mlc_device::write)
{
device_hp_hil_interface *entry = m_device_list.first();
uint16_t tmp = data | (m_w1 << 8);
DBG_LOG(2,"Write", ("%d <- %02x\n", offset, data));
switch (offset)
{
case 0:
DBG_LOG(1,"Transmit", ("%scommand 0x%02x to device %d\n", !m_loop?"loopback ":"", data, m_w1 & 7));
m_fifo.clear();
if (m_loop & 2) // no devices on 2nd link loop
return;
if (m_loop == 0)
@ -130,21 +134,13 @@ WRITE8_MEMBER(hp_hil_mlc_device::write)
}
return;
}
if ((m_w1 & 7) == 0) // broadcast
while (entry)
{
while (entry)
{
entry->hil_write(data | (m_w1 << 8));
entry = entry->next();
}
} else
{
while (entry)
{
if (entry->device_id() == (m_w1 & 7))
entry->hil_write(data | (m_w1 << 8));
entry = entry->next();
}
if (!entry->hil_write(&tmp))
break;
entry = entry->next();
}
break;
@ -228,13 +224,15 @@ void hp_hil_mlc_device::hil_write(uint16_t data)
WRITE_LINE_MEMBER(hp_hil_mlc_device::ap_w)
{
uint16_t data = HPMLC_W1_C | HPHIL_POL;
if (state && (m_w3 & HPMLC_W3_APE))
{
device_hp_hil_interface *entry = m_device_list.first();
while (entry)
{
entry->hil_write(HPMLC_W1_C | HPHIL_POL);
if (!(entry->hil_write(&data)))
break;
entry = entry->next();
}
}
@ -279,4 +277,3 @@ void device_hp_hil_interface::set_hp_hil_mlc_device()
m_hp_hil_mlc = dynamic_cast<hp_hil_mlc_device *>(m_hp_hil_mlc_dev);
m_hp_hil_mlc->add_hp_hil_device(this);
}

View File

@ -177,7 +177,7 @@ public:
// inline configuration
static void static_set_hp_hil_mlc(device_t &device, device_t *mlc_device);
virtual void hil_write(uint16_t data) { };
virtual bool hil_write(uint16_t *data) { return true; };
int device_id() { return m_device_id; };
protected: