diff --git a/src/devices/machine/psion_asic1.cpp b/src/devices/machine/psion_asic1.cpp index 75408292572..f733c55a590 100644 --- a/src/devices/machine/psion_asic1.cpp +++ b/src/devices/machine/psion_asic1.cpp @@ -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; diff --git a/src/devices/machine/psion_asic2.cpp b/src/devices/machine/psion_asic2.cpp index 26bef222a9a..e91dd370b67 100644 --- a/src/devices/machine/psion_asic2.cpp +++ b/src/devices/machine/psion_asic2.cpp @@ -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 diff --git a/src/devices/machine/psion_asic2.h b/src/devices/machine/psion_asic2.h index 64111355201..48dcfb2c690 100644 --- a/src/devices/machine/psion_asic2.h +++ b/src/devices/machine/psion_asic2.h @@ -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 auto data_r() { static_assert(N < 8); return m_data_r[N].bind(); } template 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; diff --git a/src/devices/machine/psion_asic3.cpp b/src/devices/machine/psion_asic3.cpp index 05857a342b6..d7e71866f72 100644 --- a/src/devices/machine/psion_asic3.cpp +++ b/src/devices/machine/psion_asic3.cpp @@ -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; diff --git a/src/devices/machine/psion_asic3.h b/src/devices/machine/psion_asic3.h index c2252cc3a19..7002746a23e 100644 --- a/src/devices/machine/psion_asic3.h +++ b/src/devices/machine/psion_asic3.h @@ -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 diff --git a/src/devices/machine/psion_asic4.cpp b/src/devices/machine/psion_asic4.cpp index 90c1987071e..0ed603eaa74 100644 --- a/src/devices/machine/psion_asic4.cpp +++ b/src/devices/machine/psion_asic4.cpp @@ -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: diff --git a/src/devices/machine/psion_asic5.cpp b/src/devices/machine/psion_asic5.cpp index 2f7cf0b30ea..4dfa2c17bb8 100644 --- a/src/devices/machine/psion_asic5.cpp +++ b/src/devices/machine/psion_asic5.cpp @@ -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(); +} diff --git a/src/devices/machine/psion_asic5.h b/src/devices/machine/psion_asic5.h index aa221c9b8bd..3d6a17011dc 100644 --- a/src/devices/machine/psion_asic5.h +++ b/src/devices/machine/psion_asic5.h @@ -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; diff --git a/src/devices/machine/psion_asic9.cpp b/src/devices/machine/psion_asic9.cpp index d337e27f0be..6bc54cd8332 100644 --- a/src/devices/machine/psion_asic9.cpp +++ b/src/devices/machine/psion_asic9.cpp @@ -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; diff --git a/src/devices/machine/psion_asic9.h b/src/devices/machine/psion_asic9.h index 4314e8d00ff..bdbe4ed618e 100644 --- a/src/devices/machine/psion_asic9.h +++ b/src/devices/machine/psion_asic9.h @@ -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 auto data_r() { static_assert(N < 8); return m_data_r[N].bind(); } template 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 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;