machine/psion_asic2.cpp: Added indexed control registers.

machine/psion_asic3.cpp: Re-implemented as two variants, ASIC3 and earlier ASIC5 based PSU devices.

machine/psion_asic5.cpp: Implemented UART and interrupts.

machine/psion_asic9.cpp: Added PCM sound I/O.
This commit is contained in:
Nigel Barnes 2023-07-22 16:38:36 +01:00
parent 8f98573380
commit 1af93b7319
10 changed files with 607 additions and 96 deletions

View File

@ -120,8 +120,7 @@ TIMER_CALLBACK_MEMBER(psion_asic1_device::frc)
switch (--m_frc_count)
{
case 0x0000:
m_frc_ovl ^= 1;
m_frcovl_cb(m_frc_ovl);
m_frcovl_cb(m_frc_ovl ^= 1);
m_a1_interrupt_status |= 0x20; // FrcExpired
update_interrupts();
@ -281,7 +280,7 @@ uint16_t psion_asic1_device::io_r(offs_t offset, uint16_t mem_mask)
break;
case 0x06: // A1InterruptStatus
data = m_a1_interrupt_status;
data = m_a1_interrupt_status & m_a1_interrupt_mask;
LOG("%s io_r: A1InterruptStatus => %02x\n", machine().describe_context(), data);
break;

View File

@ -36,6 +36,8 @@ psion_asic2_device::psion_asic2_device(const machine_config &mconfig, const char
, m_buzvol_cb(*this)
, m_dr_cb(*this)
, m_col_cb(*this, 0xff)
, m_read_pd_cb(*this, 0x00)
, m_write_pd_cb(*this)
, m_data_r(*this, 0x00)
, m_data_w(*this)
{
@ -47,10 +49,14 @@ psion_asic2_device::psion_asic2_device(const machine_config &mconfig, const char
void psion_asic2_device::device_start()
{
m_a2_status = 0x01;
m_a2_status = 0x00;
m_busy_timer = timer_alloc(FUNC(psion_asic2_device::busy), this);
save_item(NAME(m_a2_index));
save_item(NAME(m_a2_icontrol0));
save_item(NAME(m_a2_icontrol1));
save_item(NAME(m_a2_iddr));
save_item(NAME(m_a2_control1));
save_item(NAME(m_a2_control2));
save_item(NAME(m_a2_control3));
@ -66,12 +72,17 @@ void psion_asic2_device::device_start()
void psion_asic2_device::device_reset()
{
m_a2_index = 0x00;
m_a2_icontrol0 = 0x00;
m_a2_icontrol1 = 0x00;
m_a2_iddr = 0x00;
m_a2_control1 = 0x00;
m_a2_control2 = 0x00;
m_a2_control3 = 0x00;
m_a2_serial_data = 0x00;
m_a2_serial_control = 0x00;
m_a2_interrupt_status = 0x00;
m_a2_status = 0x00;
m_a2_channel_control = 0x00;
}
@ -86,6 +97,16 @@ void psion_asic2_device::on_clr_w(int state)
update_interrupts();
}
void psion_asic2_device::sds_int_w(int state)
{
if (state)
m_a2_status |= 0x20; // A2Sdis
else
m_a2_status &= ~0x20;
update_interrupts();
}
void psion_asic2_device::dnmi_w(int state)
{
if (state)
@ -112,7 +133,7 @@ void psion_asic2_device::reset_w(int state)
void psion_asic2_device::update_interrupts()
{
int irq = m_a2_status & 0x01;
int irq = m_a2_status & 0x21;
int nmi = BIT(m_a2_interrupt_status, 0, 2) & BIT(m_a2_control3, 4, 2);
m_int_cb(irq ? ASSERT_LINE : CLEAR_LINE);
@ -136,6 +157,32 @@ uint8_t psion_asic2_device::io_r(offs_t offset)
switch (offset & 7)
{
case 0x00: // A2Index - Index Register
data = m_a2_index;
LOG("%s io_r: A2Index => %02x\n", machine().describe_context(), data);
break;
case 0x01: // A2Control - Indexed Control Register
switch (m_a2_index)
{
case 0: // A2IControl0 - System Control Register 0
data = m_a2_icontrol0;
LOG("%s io_r: A2IControl0 => %02x\n", machine().describe_context(), data);
break;
case 1: // A2IControl1 - Serial Clock Control Register
data = m_a2_icontrol1;
LOG("%s io_r: A2IControl1 => %02x\n", machine().describe_context(), data);
break;
case 2: // A2IWrite - Port Output Data Register (Write only)
LOG("%s io_r: A2IWrite => %02x\n", machine().describe_context(), data);
break;
case 3: // A2IDDR - Port Data Direction Register
data = m_a2_iddr;
LOG("%s io_r: A2IDDR => %02x\n", machine().describe_context(), data);
break;
}
break;
case 0x02: // A2External - External status register
switch (m_a2_control1 & 0x0f)
{
@ -161,6 +208,9 @@ uint8_t psion_asic2_device::io_r(offs_t offset)
// b2 SlaveDataValid - Slave data valid, 1 if valid frame arrived
// b3 SlaveDataControl - Slave control or data frame, 1 if control frame
// b4 SlaveDataOverrun - Slave data overrun, 1 if overrun
// b5 LowBatteryNMI - Low battery NMI, 1 if NMI occurred
// b6 0
// b7 0
data = m_a2_interrupt_status;
LOG("%s io_r: A2InterruptStatus => %02x\n", machine().describe_context(), data);
break;
@ -172,6 +222,8 @@ uint8_t psion_asic2_device::io_r(offs_t offset)
// b3 SerialClockState - 1 if slave clock is high
// b4 SerialBusy - 1 while data serial controller is busy
// b5 A2Sdis - 1 if slave data signal is high
// b6 Ext - 1 in Extended Mode, 0 in Compatible Mode
// b7 RevId - 1 if Revision 4 part
data = m_a2_status;
if (!machine().side_effects_disabled())
{
@ -189,7 +241,8 @@ uint8_t psion_asic2_device::io_r(offs_t offset)
break;
case 0x06: // A2KeyData - Keyboard poll register
data = m_col_cb(m_a2_control1 & 0x0f);
// Extended mode read from Port I/O lines
data = m_read_pd_cb();
LOG("%s io_r: A2KeyData => %02x\n", machine().describe_context(), data);
break;
@ -209,6 +262,45 @@ void psion_asic2_device::io_w(offs_t offset, uint8_t data)
{
switch (offset & 7)
{
case 0x00: // A2Index - Index Register
// b0-b1 INDEX0,1 - Register 1 Index
LOG("%s io_w: A2Index <= %02x\n", machine().describe_context(), data);
m_a2_index = data & 3;
break;
case 0x01: // A2Control - Indexed Control Register
switch (m_a2_index)
{
case 0: // A2IControl0 - System Control Register 0
// b0-b1 CLKSEL0-1 - Crystal Divider Select (0,1 - 23.04MHz divider = 3, 2 - 15.36MHz divider = 2, 3 - 7.68MHz divider = 1)
// b2 CHEN3 - Serial Channel 3 is enabled when this bit is set
// b3 CHEN4 - Serial Channel 4 is enabled when this bit is set
// b4 CHEN6 - Serial Channel 6 is enabled when this bit is set
// b5 EXONOFF - EXON & SCKS witch-on is disabled when this bit is set
// b6 INTSEL - Interrupt Source Select (0 - Frame received, 1 - SDIS direct)
LOG("%s io_w: A2IControl0 => %02x\n", machine().describe_context(), data);
m_a2_icontrol0 = data;
break;
case 1: // A2IControl1 - Serial Clock Control Register
// b0 CKEN1 - Serial Channel 1 continuous clock is enabled when this bit is set
// b1 CKEN2 - Serial Channel 2 continuous clock is enabled when this bit is set
// b2 CKEN3 - Serial Channel 3 continuous clock is enabled when this bit is set
// b3 CKEN4 - Serial Channel 4 continuous clock is enabled when this bit is set
LOG("%s io_w: A2IControl1 => %02x\n", machine().describe_context(), data);
m_a2_icontrol1 = data;
break;
case 2: // A2IWrite - Port Output Data Register
LOG("%s io_w: A2IWrite => %02x\n", machine().describe_context(), data);
m_write_pd_cb(data & m_a2_iddr);
break;
case 3: // A2IDDR - Port Data Direction Register
// b0-b7 DO0-7 - 0 = PD* is and input, 1 = PD* is an output
LOG("%s io_w: A2IDDR => %02x\n", machine().describe_context(), data);
m_a2_iddr = data;
break;
}
break;
case 0x02: // A2Control1 - Control register 1
// b0-b3 KeyScan - Values 0-15 drive the keyboard poll columns
// b4-b5 SerialClockRate - Sets the clock frequency for channels 1-4 and 7 as below:
@ -217,7 +309,6 @@ void psion_asic2_device::io_w(offs_t offset, uint8_t data)
// 3 = ClockRateFast 3.84 MHz
LOG("%s io_w: A2Control1 <= %02x\n", machine().describe_context(), data);
m_a2_control1 = data;
//m_a2_external = m_col_cb(data & 0x0f);
break;
case 0x03: // A2Control2 - Control register 2

View File

@ -32,6 +32,8 @@ public:
auto buzvol_cb() { return m_buzvol_cb.bind(); }
auto dr_cb() { return m_dr_cb.bind(); }
auto col_cb() { return m_col_cb.bind(); }
auto read_pd_cb() { return m_read_pd_cb.bind(); }
auto write_pd_cb() { return m_write_pd_cb.bind(); }
template <unsigned N> auto data_r() { static_assert(N < 8); return m_data_r[N].bind(); }
template <unsigned N> auto data_w() { static_assert(N < 8); return m_data_w[N].bind(); }
@ -40,6 +42,7 @@ public:
void io_w(offs_t offset, uint8_t data);
void on_clr_w(int state);
void sds_int_w(int state);
void dnmi_w(int state);
void frcovl_w(int state);
void reset_w(int state);
@ -51,6 +54,10 @@ protected:
private:
void update_interrupts();
uint8_t m_a2_index;
uint8_t m_a2_icontrol0;
uint8_t m_a2_icontrol1;
uint8_t m_a2_iddr;
uint8_t m_a2_control1;
uint8_t m_a2_control2;
uint8_t m_a2_control3;
@ -59,7 +66,6 @@ private:
uint8_t m_a2_interrupt_status;
uint8_t m_a2_status;
uint8_t m_a2_channel_control;
//uint8_t m_a2_external;
devcb_write_line m_int_cb;
devcb_write_line m_nmi_cb;
@ -68,6 +74,8 @@ private:
devcb_write_line m_buzvol_cb;
devcb_write_line m_dr_cb;
devcb_read8 m_col_cb;
devcb_read8 m_read_pd_cb;
devcb_write8 m_write_pd_cb;
devcb_read8::array<8> m_data_r;
devcb_write16::array<8> m_data_w;

View File

@ -2,7 +2,7 @@
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC3
Psion ASIC3/PS34
MC and HC power supplies are based on a full custom liner ASIC known as ASIC3.
This custom chip is manufactured by Maxim and has the Maxim part number MAX616.
@ -21,18 +21,28 @@
#include "logmacro.h"
DEFINE_DEVICE_TYPE(PSION_ASIC3, psion_asic3_device, "psion_asic3", "Psion ASIC3")
DEFINE_DEVICE_TYPE(PSION_PSU_ASIC3, psion_psu_asic3_device, "psion_psu_asic3", "Psion PSU (ASIC3)")
DEFINE_DEVICE_TYPE(PSION_PSU_ASIC5, psion_psu_asic5_device, "psion_psu_asic5", "Psion PSU (ASIC5)")
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
psion_asic3_device::psion_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PSION_ASIC3, tag, owner, clock)
psion_asic3_device::psion_asic3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, type, tag, owner, clock)
, m_adin_cb(*this, 0)
{
}
psion_psu_asic5_device::psion_psu_asic5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: psion_asic3_device(mconfig, PSION_PSU_ASIC5, tag, owner, clock)
{
}
psion_psu_asic3_device::psion_psu_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: psion_asic3_device(mconfig, PSION_PSU_ASIC3, tag, owner, clock)
{
}
//-------------------------------------------------
// device_start - device-specific startup
@ -40,7 +50,9 @@ psion_asic3_device::psion_asic3_device(const machine_config &mconfig, const char
void psion_asic3_device::device_start()
{
save_item(NAME(m_a3_status));
save_item(NAME(m_a3_control1));
save_item(NAME(m_a3_control2));
save_item(NAME(m_a3_control3));
}
//-------------------------------------------------
@ -49,7 +61,9 @@ void psion_asic3_device::device_start()
void psion_asic3_device::device_reset()
{
m_a3_status = 0x00;
m_a3_control1 = 0x00;
m_a3_control2 = 0x00;
m_a3_control3 = 0x00;
}
@ -57,21 +71,16 @@ void psion_asic3_device::device_reset()
// READ/WRITE HANDLERS
//**************************************************************************
void psion_asic3_device::data_w(uint16_t data)
void psion_psu_asic5_device::data_w(uint16_t data)
{
switch (data & 0x300)
{
case NULL_FRAME:
device_reset();
break;
case CONTROL_FRAME:
m_sibo_control = data & 0xff;
switch (m_sibo_control & 0xc0)
{
case 0x80: // SerialWrite
break;
}
break;
case DATA_FRAME:
@ -103,26 +112,23 @@ void psion_asic3_device::data_w(uint16_t data)
m_a3_control2 = data;
break;
case 0x04: // A3Dummy1
LOG("%s data_w: A3Dummy1 register %02x\n", machine().describe_context(), data);
break;
case 0x07: // A3Control3
// b0 xDummy1
// b0 0
// b1 OffEnable
// b2 AdcReadHighEnable
// b3-b7 0
LOG("%s data_w: A3Control3 register %02x\n", machine().describe_context(), data);
m_a3_control3 = data;
break;
default:
LOG("%s data_w: Unhandled register %02x\n", machine().describe_context(), m_sibo_control & 0x0f);
LOG("%s data_w: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
break;
}
}
}
uint8_t psion_asic3_device::data_r()
uint8_t psion_psu_asic5_device::data_r()
{
uint8_t data = 0x00;
@ -137,6 +143,7 @@ uint8_t psion_asic3_device::data_r()
switch (m_sibo_control & 0x0f)
{
case 0x00: // A3Adc
{
// A3AdcLsbR
// b0-b6 OtherBits
// b7 InvertedBit
@ -144,29 +151,148 @@ uint8_t psion_asic3_device::data_r()
// b0-b3 AdcBits
// b4 Overrange
// b5 Polarity
uint16_t data_in = 0;
switch (BIT(m_a3_control2, 6, 2)) // AnalogueMultiplex
{
case 0: // AdcDigitizer
data_in = m_adin_cb();
break;
case 1: // AdcVh
break;
case 2: // AdcMainBattery
data_in = 0x7ff;
break;
case 3: // AdcLithiumBattery
data_in = 0x7ff;
break;
}
if (BIT(m_a3_control3, 2)) // AdcReadHighEnable
data = BIT(m_adin_cb(), 8, 4);
data = BIT(data_in, 8, 4);
else
data = (m_adin_cb() & 0xff) ^ 0x80;
LOG("%s data_r: A3Adc register %02x\n", machine().describe_context(), data);
data = (data_in & 0xff) ^ 0x80;
LOG("%s data_r: A3Adc %d register %02x\n", machine().describe_context(), BIT(m_a3_control2, 6, 2), data);
break;
}
case 0x0d: // A3Status
// b0-b2 Admsb
// b3 Nc
// b4 Penup
// b5 Vhready
// b6 ColdStart
// b7 PowerFail
// b0 ColdStart
// b1 PowerFail
data = 0x40;
data = 0x00; // ColdStart
LOG("%s data_r: A3Status register %02x\n", machine().describe_context(), data);
break;
default:
LOG("%s data_r: Unhandled register %02x\n", machine().describe_context(), m_sibo_control & 0x0f);
LOG("%s data_r: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
break;
}
break;
}
return data;
}
void psion_psu_asic3_device::data_w(uint16_t data)
{
switch (data & 0x300)
{
case NULL_FRAME:
device_reset();
break;
case CONTROL_FRAME:
m_sibo_control = data & 0xff;
break;
case DATA_FRAME:
data &= 0xff;
switch (m_sibo_control & 0x0f)
{
case 0x00: // PS34W_CONTROL
// b0-b1 Vhpower
// b2 Vh
// b3 Vcc5
// b4 Vee2
// b5 Vcc4
// b6 Vee1
// b7 Vcc3
LOG("%s data_w: PS34W_CONTROL %02x\n", machine().describe_context(), data);
m_a3_control1 = data;
break;
case 0x01: // PS34W_DTOA
// b0-b4 Dac
// b5-b6 Adcsel
// b7 Ncc
LOG("%s data_w: PS34W_DTOA %02x\n", machine().describe_context(), data);
m_a3_control2 = data;
break;
default:
LOG("%s data_w: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
break;
}
}
}
uint8_t psion_psu_asic3_device::data_r()
{
uint8_t data = 0x00;
switch (m_sibo_control & 0xc0)
{
case 0x40: // SerialSelect
if (m_sibo_control == 0x43) // A3SelectId
data = 0x80; // A3InfoByte
break;
case 0xc0: // SerialRead
switch (m_sibo_control & 0x0f)
{
case 0x00: // PS34R_ADC
switch (BIT(m_a3_control2, 5, 2)) // Adcsel
{
case 0: // ADCSEL_ADCIN
data = m_adin_cb() & 0xff;
break;
case 1: // ADCSEL_VIN
data = 0xff;
break;
case 2: // ADCSEL_VH
break;
case 3: // ADCSEL_VBATT
data = 0xff;
break;
}
LOG("%s data_r: PS34R_ADC %d %02x\n", machine().describe_context(), BIT(m_a3_control2, 5, 2), data);
break;
case 0x01: // PS34R_STATUS
// b0-b2 Admsb
// b3 Nc
// b4 Penup
// b5 Vhready
// b6 ColdStart
// b7 PowerFail
switch (BIT(m_a3_control2, 5, 2)) // Adcsel
{
case 0: // ADCSEL_ADCIN
data = BIT(m_adin_cb(), 8, 3);
break;
case 1: // ADCSEL_VIN
data = 0x07;
break;
case 2: // ADCSEL_VH
break;
case 3: // ADCSEL_VBATT
data = 0x07;
break;
}
data |= 0x40; // ColdStart
LOG("%s data_r: PS34R_STATUS %02x\n", machine().describe_context(), data);
break;
default:
LOG("%s data_r: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data);
break;
}
break;

View File

@ -2,7 +2,7 @@
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC3
Psion ASIC3/PS34
******************************************************************************/
@ -21,19 +21,18 @@
class psion_asic3_device : public device_t
{
public:
psion_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
// callbacks
auto adin_cb() { return m_adin_cb.bind(); }
void data_w(uint16_t data);
uint8_t data_r();
virtual void data_w(uint16_t data) { }
virtual uint8_t data_r() { return 0x00; }
protected:
psion_asic3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0);
virtual void device_start() override;
virtual void device_reset() override;
private:
static constexpr uint16_t NULL_FRAME = 0x000;
static constexpr uint16_t CONTROL_FRAME = 0x100;
static constexpr uint16_t DATA_FRAME = 0x200;
@ -44,11 +43,37 @@ private:
uint8_t m_a3_control1;
uint8_t m_a3_control2;
uint8_t m_a3_control3;
uint8_t m_a3_status;
};
// ======================> psion_psu_asic5_device
class psion_psu_asic5_device : public psion_asic3_device
{
public:
// construction/destruction
psion_psu_asic5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual void data_w(uint16_t data) override;
virtual uint8_t data_r() override;
};
// ======================> psion_psu_asic3_device
class psion_psu_asic3_device : public psion_asic3_device
{
public:
// construction/destruction
psion_psu_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
virtual void data_w(uint16_t data) override;
virtual uint8_t data_r() override;
};
// device type definition
DECLARE_DEVICE_TYPE(PSION_ASIC3, psion_asic3_device)
DECLARE_DEVICE_TYPE(PSION_PSU_ASIC3, psion_psu_asic3_device)
DECLARE_DEVICE_TYPE(PSION_PSU_ASIC5, psion_psu_asic5_device)
#endif // MAME_MACHINE_PSION_ASIC3_H

View File

@ -82,6 +82,7 @@ void psion_asic4_device::data_w(uint16_t data)
switch (data & 0x300)
{
case NULL_FRAME:
device_reset();
break;
case CONTROL_FRAME:

View File

@ -22,16 +22,13 @@
Peripheral Mode Type
0 x x 0 x x x x 1 RS232 port
x x 0 x x x 1 x Centronics (Parallel) port
x x 0 x x 1 x X ROM
x x 0 x 1 x x X Magnetic Card Reader
x x 0 x x 1 x x ROM
x x 0 x 1 x x x Magnetic Card Reader
x x 0 0 x x x x Barcode reader
x x 0 1 x x x x USA modem
x 1 0 x x x x x Modem
1 x 0 x x x x x RS232 TTL
TODO:
- implement UART
******************************************************************************/
#include "emu.h"
@ -55,11 +52,20 @@ psion_asic5_device::psion_asic5_device(const machine_config &mconfig, const char
, m_mode(~uint8_t(0))
, m_in_a_handler(*this, 0)
, m_in_b_handler(*this, 0)
, m_in_c_handler(*this, 0)
, m_out_a_handler(*this)
, m_out_b_handler(*this)
, m_out_c_handler(*this)
, m_out_d_handler(*this)
, m_out_e_handler(*this)
, m_out_cs_handler(*this)
, m_int_handler(*this)
, m_txd_handler(*this)
, m_rts_handler(*this)
, m_dtr_handler(*this)
, m_rxd(0)
, m_cts(0)
, m_dsr(0)
, m_dcd(0)
{
}
@ -84,8 +90,11 @@ void psion_asic5_device::device_start()
save_item(NAME(m_port_b_counter));
save_item(NAME(m_port_b_latch));
save_item(NAME(m_port_b_mode));
save_item(NAME(m_port_dc_writes));
save_item(NAME(m_port_dc_select));
save_item(NAME(m_int_mask));
save_item(NAME(m_int_status));
save_item(NAME(m_control));
save_item(NAME(m_bdr));
}
//-------------------------------------------------
@ -97,6 +106,50 @@ void psion_asic5_device::device_reset()
m_port_b_counter = 0x00;
m_port_b_latch = 0x00;
m_port_b_mode = 0x00;
m_port_dc_select = false;
m_int_mask = 0x00;
m_int_status = 0x02; // UART transmitter empty
m_control = 0x00;
m_bdr = 0xffff;
receive_register_reset();
transmit_register_reset();
}
void psion_asic5_device::update_interrupts()
{
int irq = m_int_status & m_int_mask;
m_int_handler(irq ? ASSERT_LINE : CLEAR_LINE);
}
void psion_asic5_device::rcv_callback()
{
if (BIT(m_port_b_mode, 0)) // UART enabled
receive_register_update_bit(m_rxd);
}
void psion_asic5_device::rcv_complete()
{
if (is_receive_framing_error() || is_receive_parity_error())
m_int_status |= 0x04;
m_int_status |= 0x01;
update_interrupts();
}
void psion_asic5_device::tra_callback()
{
if (BIT(m_port_b_mode, 0)) // UART enabled
m_txd_handler(transmit_register_get_data_bit());
}
void psion_asic5_device::tra_complete()
{
m_int_status |= 0x02;
update_interrupts();
}
@ -109,6 +162,7 @@ void psion_asic5_device::data_w(uint16_t data)
switch (data & 0x300)
{
case NULL_FRAME:
device_reset();
break;
case CONTROL_FRAME:
@ -118,7 +172,7 @@ void psion_asic5_device::data_w(uint16_t data)
{
case 0x80: // SerialWrite
if (m_sibo_control == 0x93) // Multi Port D and C writes
m_port_dc_writes = 0;
m_port_dc_select = false;
break;
}
break;
@ -138,61 +192,110 @@ void psion_asic5_device::data_w(uint16_t data)
case 0x01: // Port B write data
LOG("%s data_w: Port B write data %02x\n", machine().describe_context(), data);
if (BIT(m_port_b_mode, 1, 2) == 1) // Latch mode
if (BIT(m_port_b_mode, 1, 2) == 1 && !BIT(m_control, 3)) // Latch mode
{
m_out_b_handler(m_port_b_latch = data);
}
break;
case 0x02: // Port B control
// b0 0 Memory mode, 1 Peripheral mode - enables UART
// b1 Port B mode
// b2 Port B mode
// b3 0 Normal mode, 1 Test mode
// b4 Not used
// b5 Not used
// b6 Not used
// b7 Not used
//
// Port B mode
// b2 b1 Mode
// 0 0 Counter mode
// 0 1 Latch mode
// 1 0 Baud rate out on port B
// 1 1 Test bus output on port B
LOG("%s data_w: Port B mode %02x\n", machine().describe_context(), data);
m_port_b_mode = data;
break;
case 0x03: // Port D and C write data
if (m_port_dc_writes)
switch (BIT(m_port_b_mode, 0))
{
LOG("%s data_w: Port C write data %02x\n", machine().describe_context(), data);
m_out_c_handler(data);
}
else
{
LOG("%s data_w: Port D write data %02x\n", machine().describe_context(), data);
m_out_d_handler(data);
if (BIT(m_port_b_mode, 1, 2) == 0) // Counter mode
case 0:
if (m_port_dc_select)
{
m_out_b_handler(m_port_b_counter = 0);
LOG("%s data_w: Port C write data %02x\n", machine().describe_context(), data);
m_out_c_handler(data);
}
else
{
LOG("%s data_w: Port D write data %02x\n", machine().describe_context(), data);
m_out_d_handler(data);
if (BIT(m_port_b_mode, 1, 2) == 0) // Counter mode
{
m_out_b_handler(m_port_b_counter = 0);
}
}
m_port_dc_select = true;
break;
case 1: // UART enabled
m_rts_handler(BIT(data, 1));
m_dtr_handler(BIT(data, 2));
break;
}
m_port_dc_writes++;
break;
case 0x06: // Interrupt mask write
// b0 UART - UART character received
// b1 UART - UART transmitter empty
// b2 UART - UART error or modem line status change
// b3 PC7 - Barcode switch/general interrupt
// b4 SR - Synchronous port1 character received
// b5 SR - Synchronous port2 character received
// b6 PC4 - Barcode data/general interrupt
// b7 PA4 - Centronics busy low/general interrupt
LOG("%s data_w: Interrupt mask write %02x\n", machine().describe_context(), data);
m_int_mask = data;
update_interrupts();
break;
case 0x07: // Control register
LOG("%s data_w: Control register %02x\n", machine().describe_context(), data);
m_out_e_handler(data & 7);
m_control = data;
m_out_cs_handler(data & 7);
break;
case 0x08: // UART Control register
// b0 Generate break character
// b1 Character length 1
// b2 Character length 2
// b3 Parity enabled if set
// b4 Odd parity if, even if clear
// b5 Set for two stop bits, clear for one
// b6 Not used
// b7 Not used
LOG("%s data_w: UART Control register %02x\n", machine().describe_context(), data);
set_data_frame(1, 5 + BIT(data, 1, 2), BIT(data, 3) ? (BIT(data, 4) ? PARITY_ODD : PARITY_EVEN) : PARITY_NONE, BIT(data, 5) ? STOP_BITS_2 : STOP_BITS_1);
receive_register_reset();
transmit_register_reset();
break;
case 0x09: // UART Transmit holding register
LOG("%s data_w: UART Transmit holding register %02x\n", machine().describe_context(), data);
transmit_register_setup(data);
m_int_status &= ~0x02;
update_interrupts();
break;
case 0x0a: // UART Baud rate LSB
LOG("%s data_w: UART Baud rate LSB %02x\n", machine().describe_context(), data);
break;
case 0x0b: // UART Baud rate MSB
LOG("%s data_w: UART Baud rate MSB %02x\n", machine().describe_context(), data);
case 0x0a:
case 0x0b: // UART Baud rate
switch (m_sibo_control & 1)
{
case 0: m_bdr = (m_bdr & 0xff00) | (data << 0); break; // LSB
case 1: m_bdr = (m_bdr & 0x00ff) | (data << 8); break; // MSB
}
LOG("%s data_w: UART Baud rate divisor %04x, Baud rate %d\n", machine().describe_context(), m_bdr, clock() / 16 / (1 - m_bdr));
set_rate(clock() / 16 / (1 - m_bdr));
break;
case 0x0c: // Port 1 and 2 reset
@ -258,16 +361,39 @@ uint8_t psion_asic5_device::data_r()
LOG("%s data_r: Interrupt mask read %02x\n", machine().describe_context(), data);
break;
case 0x07: // Interrupt status read
data = m_int_status & m_int_mask;
LOG("%s data_r: Interrupt status read %02x\n", machine().describe_context(), data);
break;
case 0x08: // UART Status register
data |= is_transmit_register_empty() ? 1 << 3 : 0;
data |= is_receive_framing_error() ? 1 << 6 : 0;
data |= is_receive_parity_error() ? 1 << 7 : 0;
// b0 State of the CTS line (PA1)
// b1 State of the DSR line (PA2)
// b2 State of the DCD line (PA3)
// b3 Transmitter buffer empty
// b4 Transmitter busy
// b5 Receive data waiting
// b6 Overrun or framing error
// b7 Parity error
data |= m_cts << 0;
data |= m_dsr << 1;
data |= m_dcd << 2;
data |= is_transmit_register_empty() ? 1 << 3 : 0;
data |= !is_transmit_register_empty() ? 1 << 4 : 0;
data |= is_receive_register_full() ? 1 << 5 : 0;
data |= is_receive_framing_error() ? 1 << 6 : 0;
data |= is_receive_parity_error() ? 1 << 7 : 0;
LOG("%s data_r: UART Status register %02x\n", machine().describe_context(), data);
m_int_status &= ~0x04;
update_interrupts();
break;
case 0x09: // UART Receive register
receive_register_extract();
data = get_received_char();
LOG("%s data_r: UART Receive register %02x\n", machine().describe_context(), data);
m_int_status &= ~0x01;
update_interrupts();
break;
case 0x0c: // Synchronous Port 1 read
@ -275,10 +401,14 @@ uint8_t psion_asic5_device::data_r()
break;
case 0x0d: // Barcode read data
// 0 PC4 4 PB4
// 1 PC7 5 PB5
// 2 PB2 6 PB6
// 3 PB3 7 PB7
// b0 PC4
// b1 PC7
// b2 PB2
// b3 PB3
// b4 PB4
// b5 PB5
// b6 PB6
// b7 PB7
LOG("%s data_r: Barcode read data %02x\n", machine().describe_context(), data);
break;
@ -295,3 +425,34 @@ uint8_t psion_asic5_device::data_r()
return data;
}
void psion_asic5_device::write_rxd(int state)
{
m_rxd = state;
device_serial_interface::rx_w(state);
}
void psion_asic5_device::write_cts(int state)
{
if (m_cts != state)
m_int_status |= 0x04;
m_cts = state;
update_interrupts();
}
void psion_asic5_device::write_dsr(int state)
{
if (m_dsr != state)
m_int_status |= 0x04;
m_dsr = state;
update_interrupts();
}
void psion_asic5_device::write_dcd(int state)
{
if (m_dcd != state)
m_int_status |= 0x04;
m_dcd = state;
update_interrupts();
}

View File

@ -31,16 +31,30 @@ public:
psion_asic5_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
static constexpr feature_type imperfect_features() { return feature::COMMS; }
void set_mode(pc6_state mode) { m_mode = mode; }
auto readpa_handler() { return m_in_a_handler.bind(); }
auto readpb_handler() { return m_in_b_handler.bind(); }
auto readpc_handler() { return m_in_c_handler.bind(); }
auto writepa_handler() { return m_out_a_handler.bind(); }
auto writepb_handler() { return m_out_b_handler.bind(); }
auto writepc_handler() { return m_out_c_handler.bind(); }
auto writepd_handler() { return m_out_d_handler.bind(); }
auto writepe_handler() { return m_out_e_handler.bind(); }
auto writecs_handler() { return m_out_cs_handler.bind(); }
// UART handlers
auto int_handler() { return m_int_handler.bind(); }
auto txd_handler() { return m_txd_handler.bind(); }
auto rts_handler() { return m_rts_handler.bind(); }
auto dtr_handler() { return m_dtr_handler.bind(); }
void write_rxd(int state);
void write_cts(int state);
void write_dsr(int state);
void write_dcd(int state);
void set_info_byte(uint8_t info) { m_info_byte = info; }
@ -53,26 +67,48 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
// device_serial overrides
virtual void rcv_callback() override;
virtual void rcv_complete() override;
virtual void tra_callback() override;
virtual void tra_complete() override;
private:
static constexpr uint16_t NULL_FRAME = 0x000;
static constexpr uint16_t CONTROL_FRAME = 0x100;
static constexpr uint16_t DATA_FRAME = 0x200;
void update_interrupts();
uint8_t m_mode;
devcb_read8 m_in_a_handler;
devcb_read8 m_in_b_handler;
devcb_read8 m_in_c_handler;
devcb_write8 m_out_a_handler;
devcb_write8 m_out_b_handler;
devcb_write8 m_out_c_handler;
devcb_write8 m_out_d_handler;
devcb_write8 m_out_e_handler;
devcb_write8 m_out_cs_handler;
devcb_write_line m_int_handler;
devcb_write_line m_txd_handler;
devcb_write_line m_rts_handler;
devcb_write_line m_dtr_handler;
int m_rxd;
int m_cts;
int m_dsr;
int m_dcd;
uint8_t m_port_b_counter;
uint8_t m_port_b_latch;
uint8_t m_port_b_mode;
uint8_t m_port_dc_writes;
bool m_port_dc_select;
uint8_t m_int_mask;
uint8_t m_int_status;
uint8_t m_control;
int16_t m_bdr;
uint8_t m_info_byte;
uint8_t m_sibo_control;

View File

@ -13,7 +13,7 @@
TODO:
- improve RAM configuration for mx machines
- set RTC timer
- ASIC9MX implements V30MX, and likely the unknown Temic device found in 3c/Siena
- ASIC9MX implements V30MX, and likely the Temic (Condor) device found in 3c/Siena
******************************************************************************/
@ -50,10 +50,13 @@ psion_asic9_device::psion_asic9_device(const machine_config &mconfig, device_typ
, m_frc2_timer(nullptr)
, m_watchdog_timer(nullptr)
, m_rtc_timer(nullptr)
, m_snd_timer(nullptr)
, m_buz_cb(*this)
, m_col_cb(*this)
, m_port_ab_r(*this, 0)
, m_port_ab_w(*this)
, m_pcm_in(*this, 0)
, m_pcm_out(*this)
, m_data_r(*this, 0x00)
, m_data_w(*this)
{
@ -147,6 +150,7 @@ void psion_asic9_device::device_start()
m_frc2_timer = timer_alloc(FUNC(psion_asic9_device::frc2), this);
m_watchdog_timer = timer_alloc(FUNC(psion_asic9_device::watchdog), this);
m_rtc_timer = timer_alloc(FUNC(psion_asic9_device::rtc), this);
m_snd_timer = timer_alloc(FUNC(psion_asic9_device::snd), this);
m_busy_timer = timer_alloc(FUNC(psion_asic9_device::busy), this);
m_a9_control = 0x00;
@ -186,6 +190,7 @@ void psion_asic9_device::device_reset()
m_frc2_timer->adjust(attotime::from_hz(512000), 0, attotime::from_hz(512000));
m_watchdog_timer->adjust(attotime::from_hz(4), 0, attotime::from_hz(4));
m_rtc_timer->adjust(attotime::from_hz(1), 0, attotime::from_hz(1));
m_snd_timer->adjust(attotime::from_hz(8000), 0, attotime::from_hz(8000)); // unknown data rate
m_post = 0x00;
@ -196,6 +201,7 @@ void psion_asic9_device::device_reset()
m_frc1_reload = 0;
m_frc2_count = 0;
m_frc2_reload = 0;
m_buz_toggle = 0;
m_watchdog_count = 0;
m_a9_protection_mode = false;
m_a9_protection_lower = 0x00;
@ -208,9 +214,11 @@ void psion_asic9_device::device_reset()
m_a9_psel_8000 = 0x00;
m_a9_psel_9000 = 0x00;
m_a9_control_extra = 0x00;
m_rtc = time(nullptr) - 946684800;
m_rtc = 0;
m_a9_status |= 0x0020; // A9MMainsPresent
m_a9_status |= 0xe000; // A9MCold
m_a9_serial_control = 0x00;
m_a9_channel_select = 0x00;
}
@ -227,6 +235,10 @@ TIMER_CALLBACK_MEMBER(psion_asic9_device::frc1)
switch (--m_frc1_count)
{
case 0x0000:
if (BIT(m_a9_control_extra, 5)) // A9MBuzzFromFrc1OrTog
{
m_buz_cb(m_buz_toggle ^= 1);
}
m_a9_interrupt_status |= 0x40; // A9MFrc1
update_interrupts();
break;
@ -271,6 +283,41 @@ TIMER_CALLBACK_MEMBER(psion_asic9_device::rtc)
m_rtc++;
}
TIMER_CALLBACK_MEMBER(psion_asic9_device::snd)
{
if (BIT(m_a9_control, 11)) // A9MSoundEnable
{
switch (BIT(m_a9_control_extra, 7)) // A9MSoundDir
{
case 0:
if (!m_snd_fifo.full())
m_snd_fifo.enqueue(m_pcm_in());
if (m_snd_fifo.full())
m_a9_status |= 0x0800;
break;
case 1:
if (!m_snd_fifo.empty())
m_pcm_out(m_snd_fifo.dequeue());
if (!m_snd_fifo.full())
m_a9_status &= ~0x0800;
break;
}
m_a9_interrupt_status |= 0x01; // Sound
update_interrupts();
}
}
void psion_asic9_device::sds_int_w(int state)
{
if (state)
m_a9_interrupt_status |= 0x04; // A9MSlave
else
m_a9_interrupt_status &= ~0x04;
update_interrupts();
}
void psion_asic9_device::eint0_w(int state)
{
if (state)
@ -286,7 +333,7 @@ void psion_asic9_device::eint1_w(int state)
if (state)
m_a9_interrupt_status |= 0x10; // A9MExpIntA
else
m_a9_interrupt_status &= ~0x10;
m_a9_interrupt_status &= ~0x10;
update_interrupts();
}
@ -549,8 +596,8 @@ uint16_t psion_asic9_device::io_r(offs_t offset, uint16_t mem_mask)
case 0x06: // A9BInterruptStatus
if (ACCESSING_BITS_0_7)
{
data = m_a9_interrupt_status;
LOG("%s io_r: A1InterruptStatus => %02x\n", machine().describe_context(), data);
data = m_a9_interrupt_status & m_a9_interrupt_mask;
LOG("%s io_r: A9InterruptStatus => %02x\n", machine().describe_context(), data);
}
break;
@ -578,6 +625,9 @@ uint16_t psion_asic9_device::io_r(offs_t offset, uint16_t mem_mask)
case 0x1a: // A9BSoundData
if (ACCESSING_BITS_0_7)
{
data = m_snd_fifo.dequeue();
if (!m_snd_fifo.full())
m_a9_status &= ~0x0800;
LOG("%s io_r: A9BSoundData => %02x\n", machine().describe_context(), data);
}
break;
@ -595,12 +645,12 @@ uint16_t psion_asic9_device::io_r(offs_t offset, uint16_t mem_mask)
case 0x22: // A9WPortABDDR
if (ACCESSING_BITS_0_7)
{
data = m_a9_port_ab_ddr & 0x00ff;
data |= m_a9_port_ab_ddr & 0x00ff;
LOG("%s io_r: A9WPortADDR => %02x\n", machine().describe_context(), data);
}
if (ACCESSING_BITS_8_15)
{
data = m_a9_port_ab_ddr & 0xff00;
data |= m_a9_port_ab_ddr & 0xff00;
LOG("%s io_r: A9WPortBDDR => %02x\n", machine().describe_context(), data >> 8);
}
break;
@ -608,12 +658,12 @@ uint16_t psion_asic9_device::io_r(offs_t offset, uint16_t mem_mask)
case 0x24: // A9WPortCDData
if (ACCESSING_BITS_0_7)
{
data = 0x00;
data |= 0x00;
LOG("%s io_r: A9WPortCData => %02x\n", machine().describe_context(), data);
}
if (ACCESSING_BITS_8_15)
{
data = 0x00 << 8;
data |= 0x00 << 8;
LOG("%s io_r: A9WPortDData => %02x\n", machine().describe_context(), data >> 8);
}
break;
@ -874,6 +924,9 @@ void psion_asic9_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
if (ACCESSING_BITS_0_7)
{
LOG("%s io_w: A9BSoundData <= %04x\n", machine().describe_context(), data);
m_snd_fifo.enqueue(data & 0xff);
if (m_snd_fifo.full())
m_a9_status |= 0x0800;
}
break;

View File

@ -34,10 +34,14 @@ public:
auto col_cb() { return m_col_cb.bind(); }
auto port_ab_r() { return m_port_ab_r.bind(); }
auto port_ab_w() { return m_port_ab_w.bind(); }
auto pcm_in() { return m_pcm_in.bind(); }
auto pcm_out() { return m_pcm_out.bind(); }
template <unsigned N> auto data_r() { static_assert(N < 8); return m_data_r[N].bind(); }
template <unsigned N> auto data_w() { static_assert(N < 8); return m_data_w[N].bind(); }
address_space &io_space() const { return m_v30->space(AS_IO); }
uint16_t io_r(offs_t offset, uint16_t mem_mask);
void io_w(offs_t offset, uint16_t data, uint16_t mem_mask);
uint16_t mem_r(offs_t offset, uint16_t mem_mask);
@ -47,6 +51,7 @@ public:
IRQ_CALLBACK_MEMBER(inta_cb);
void sds_int_w(int state);
void eint0_w(int state);
void eint1_w(int state);
void eint2_w(int state);
@ -85,12 +90,14 @@ private:
emu_timer *m_frc2_timer;
emu_timer *m_watchdog_timer;
emu_timer *m_rtc_timer;
emu_timer *m_snd_timer;
TIMER_CALLBACK_MEMBER(tick);
TIMER_CALLBACK_MEMBER(frc1);
TIMER_CALLBACK_MEMBER(frc2);
TIMER_CALLBACK_MEMBER(watchdog);
TIMER_CALLBACK_MEMBER(rtc);
TIMER_CALLBACK_MEMBER(snd);
void update_interrupts();
bool is_protected(offs_t offset);
@ -111,11 +118,12 @@ private:
uint16_t m_frc1_reload;
uint16_t m_frc2_count;
uint16_t m_frc2_reload;
int m_buz_toggle;
uint8_t m_watchdog_count;
bool m_a9_protection_mode;
uint32_t m_a9_protection_upper;
uint32_t m_a9_protection_lower;
uint8_t m_a9_port_ab_ddr;
uint16_t m_a9_port_ab_ddr;
uint8_t m_a9_port_c_ddr;
uint8_t m_a9_port_d_ddr;
uint8_t m_a9_psel_6000;
@ -124,6 +132,7 @@ private:
uint8_t m_a9_psel_9000;
uint16_t m_a9_control_extra;
uint32_t m_rtc;
util::fifo<uint8_t, 16> m_snd_fifo;
uint8_t m_a9_serial_data;
uint8_t m_a9_serial_control;
@ -133,6 +142,8 @@ private:
devcb_write8 m_col_cb;
devcb_read16 m_port_ab_r;
devcb_write16 m_port_ab_w;
devcb_read8 m_pcm_in;
devcb_write8 m_pcm_out;
devcb_read8::array<8> m_data_r;
devcb_write16::array<8> m_data_w;