From 469c2906d96a0cec96ab5940d5890eb6c11f8ef9 Mon Sep 17 00:00:00 2001 From: Nigel Barnes Date: Sat, 25 Mar 2023 12:23:20 +0000 Subject: New systems marked not working ------------------------------ Series 3a [Nigel Barnes, The Last Psion] Series 3c [Nigel Barnes, The Last Psion] Series 3mx [Nigel Barnes, The Last Psion] Siena [Nigel Barnes, The Last Psion] Workabout [Nigel Barnes, The Last Psion] Workabout mx [Nigel Barnes, The Last Psion] New clones marked not working ----------------------------- Pocket Book II [Nigel Barnes, The Last Psion] Series 3a (2M) [Nigel Barnes, The Last Psion] Series 3a (2M) (German) [Nigel Barnes, The Last Psion] --- scripts/src/machine.lua | 15 + src/devices/machine/psion_asic5.cpp | 225 +++++++ src/devices/machine/psion_asic5.h | 116 ++++ src/devices/machine/psion_asic9.cpp | 1134 +++++++++++++++++++++++++++++++++++ src/devices/machine/psion_asic9.h | 155 +++++ src/emu/xtal.cpp | 1 + src/mame/mame.lst | 15 + src/mame/psion/psion3a.cpp | 396 ++++++++++++ src/mame/psion/psion_ssd.cpp | 284 +++++++++ src/mame/psion/psion_ssd.h | 84 +++ src/mame/psion/siena.cpp | 226 +++++++ src/mame/psion/workabout.cpp | 265 ++++++++ 12 files changed, 2916 insertions(+) create mode 100644 src/devices/machine/psion_asic5.cpp create mode 100644 src/devices/machine/psion_asic5.h create mode 100644 src/devices/machine/psion_asic9.cpp create mode 100644 src/devices/machine/psion_asic9.h create mode 100644 src/mame/psion/psion3a.cpp create mode 100644 src/mame/psion/psion_ssd.cpp create mode 100644 src/mame/psion/psion_ssd.h create mode 100644 src/mame/psion/siena.cpp create mode 100644 src/mame/psion/workabout.cpp diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index ad603da4458..d77e3f27042 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2867,6 +2867,21 @@ if (MACHINES["PLA"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/psion_asic5.h,MACHINES["PSION_ASIC"] = true +--@src/devices/machine/psion_asic9.h,MACHINES["PSION_ASIC"] = true +--------------------------------------------------- + +if (MACHINES["PSION_ASIC"]~=null) then + files { + MAME_DIR .. "src/devices/machine/psion_asic5.cpp", + MAME_DIR .. "src/devices/machine/psion_asic5.h", + MAME_DIR .. "src/devices/machine/psion_asic9.cpp", + MAME_DIR .. "src/devices/machine/psion_asic9.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/pxa255.h,MACHINES["PXA255"] = true diff --git a/src/devices/machine/psion_asic5.cpp b/src/devices/machine/psion_asic5.cpp new file mode 100644 index 00000000000..8bd69f7e776 --- /dev/null +++ b/src/devices/machine/psion_asic5.cpp @@ -0,0 +1,225 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/****************************************************************************** + + Psion ASIC5 + + ASIC5 is a general purpose I/O chip with a built-in UART that can be set to + run in a number of different modes thereby simplifying the task of peripheral + design. For example, it is possible to set up ASIC5 to run as a Centronics + parallel port interface, an 8-bit parallel I/O port, a serial bar code + controller or a serial RS232 converter. + + TODO: + - implement peripheral mode + +******************************************************************************/ + +#include "emu.h" +#include "psion_asic5.h" + +#define VERBOSE 0 +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + + +DEFINE_DEVICE_TYPE(PSION_ASIC5_PACK, psion_asic5_pack_device, "psion_asic5_pack", "Psion ASIC5 (Pack mode)") +DEFINE_DEVICE_TYPE(PSION_ASIC5_PERIPHERAL, psion_asic5_peripheral_device, "psion_asic5_peripheral", "Psion ASIC5 (Peripheral mode)") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +psion_asic5_device::psion_asic5_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_in_a_handler(*this) + , m_in_b_handler(*this) + , m_out_a_handler(*this) + , m_out_b_handler(*this) + , m_out_c_handler(*this) + , m_out_d_handler(*this) +{ +} + +psion_asic5_pack_device::psion_asic5_pack_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : psion_asic5_device(mconfig, PSION_ASIC5_PACK, tag, owner, clock) +{ +} + +psion_asic5_peripheral_device::psion_asic5_peripheral_device(const machine_config &mconfig, const char * tag, device_t *owner, uint32_t clock) + : psion_asic5_device(mconfig, PSION_ASIC5_PERIPHERAL, tag, owner, clock) + , m_serial(*this, "serial") + //, m_irq4_callback(*this) + //, m_txd1_callback(*this) + //, m_dtr1_callback(*this) + //, m_rts1_callback(*this) +{ +} + + +void psion_asic5_peripheral_device::device_add_mconfig(machine_config &config) +{ + NS16550(config, m_serial, clock() / 13); + //m_serial->out_int_callback().set([this](int state) { m_irq4_callback(state); }); + //m_serial->out_tx_callback().set([this](int state) { m_txd1_callback(state); }); + //m_serial->out_dtr_callback().set([this](int state) { m_dtr1_callback(state); }); + //m_serial->out_rts_callback().set([this](int state) { m_rts1_callback(state); }); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void psion_asic5_device::device_start() +{ + m_in_a_handler.resolve(); + m_in_b_handler.resolve(); + m_out_a_handler.resolve_safe(); + m_out_b_handler.resolve_safe(); + m_out_c_handler.resolve_safe(); + m_out_d_handler.resolve_safe(); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void psion_asic5_device::device_reset() +{ + m_portb_ctrl = 0x00; + m_portb_counter = 0x00; +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +void psion_asic5_device::data_w(uint16_t data) +{ + switch (data & 0x300) + { + case NULL_FRAME: + break; + + case CONTROL_FRAME: + m_sibo_control = data & 0xff; + + switch (m_sibo_control & 0xc0) + { + case 0x80: // SerialWrite + //if (m_sibo_control == 0x82) // write A3Setup + if (m_sibo_control == 0x93) // Multi Port D and C writes + m_port_dc_writes = 0; + break; + } + break; + + case DATA_FRAME: + data &= 0xff; + switch (m_sibo_control & 0x0f) + { + case 0x00: // Port A write data + LOG("%s data_w: Port A write data %02x\n", machine().describe_context(), data); + m_out_a_handler(data); + break; + + case 0x01: // Port B write data + LOG("%s data_w: Port B write data %02x\n", machine().describe_context(), data); + m_out_b_handler(data); + break; + + case 0x02: // Port B control + LOG("%s data_w: Port B control %02x\n", machine().describe_context(), data); + m_portb_ctrl = data; + break; + + case 0x03: // Port D and C write data + if (m_port_dc_writes) + { + 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); + m_portb_counter = 0x00; + m_out_b_handler(m_portb_counter); + } + m_port_dc_writes++; + break; + + case 0x06: // Interrupt mask write + LOG("%s data_w: out int mask %02x\n", machine().describe_context(), data); + m_interrupt_mask = data; + break; + + //case 0x07: // Control register + // m = data; + // break; + + default: + LOG("%s data_w: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data); + break; + } + break; + } +} + + +uint8_t psion_asic5_device::data_r() +{ + uint8_t data = 0x00; + + switch (m_sibo_control & 0xc0) + { + case 0x40: // SerialSelect + if (m_sibo_control == 0x42) // Asic5PackId + data = m_info_byte; // A3InfoByte + break; + + case 0xc0: // SerialRead + switch (m_sibo_control & 0x0f) + { + case 0x00: // Port A read data + data = m_in_a_handler(); + LOG("%s data_r: Port A read data %02x\n", machine().describe_context(), data); + if (m_sibo_control & 0x90) // Multi, increment Port B + { + m_portb_counter++; + m_out_b_handler(m_portb_counter); + } + break; + + case 0x01: // Port B read data + data = m_in_b_handler(); + LOG("%s data_r: Port B read data %02x\n", machine().describe_context(), data); + break; + + case 0x02: // Port B counter + m_portb_counter++; + m_out_b_handler(m_portb_counter); + LOG("%s data_r: Port B counter %02x\n", machine().describe_context(), m_portb_counter); + break; + + case 0x06: // Interrupt mask write + data = m_interrupt_mask; + LOG("%s data_r: in int mask %02x\n", machine().describe_context(), data); + break; + + //case 0x07: // Control register + // m = data; + // break; + + default: + LOG("%s data_r: unknown control %02x data %02x\n", machine().describe_context(), m_sibo_control, data); + break; + } + break; + } + + return data; +} diff --git a/src/devices/machine/psion_asic5.h b/src/devices/machine/psion_asic5.h new file mode 100644 index 00000000000..fbd07e89d46 --- /dev/null +++ b/src/devices/machine/psion_asic5.h @@ -0,0 +1,116 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/****************************************************************************** + + Psion ASIC5 + +******************************************************************************/ + +#ifndef MAME_MACHINE_PSION_ASIC5_H +#define MAME_MACHINE_PSION_ASIC5_H + +#pragma once + +#include "machine/ins8250.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> psion_asic5_device + +class psion_asic5_device : public device_t +{ +public: + auto readpa_handler() { return m_in_a_handler.bind(); } + auto readpb_handler() { return m_in_b_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(); } + + void set_info_byte(uint8_t info) { m_info_byte = info; } + + void data_w(uint16_t data); + uint8_t data_r(); + +protected: + // construction/destruction + psion_asic5_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + 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; + + devcb_read8 m_in_a_handler; + devcb_read8 m_in_b_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; + + // Slave control mode + static constexpr uint8_t READ_WRITE_SELECT = 0xc0; + static constexpr uint8_t BYTE_WORD_TRANSFER = 0xa0; + static constexpr uint8_t SINGLE_MULTI_TRANSFER = 0x90; + + // registers + uint8_t m_portb_counter; + uint8_t m_portb_ctrl; + int m_port_dc_writes; + uint8_t m_interrupt_mask; + + // internal + uint8_t m_info_byte; + uint8_t m_sibo_control; +}; + + +// ======================> psion_asic5_pack_device + +class psion_asic5_pack_device : public psion_asic5_device +{ +public: + // construction/destruction + psion_asic5_pack_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); +}; + + +// ======================> psion_asic5_peripheral_device + +class psion_asic5_peripheral_device : public psion_asic5_device +{ +public: + // construction/destruction + psion_asic5_peripheral_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + //auto irq4() { return m_irq4_callback.bind(); } + //auto txd1() { return m_txd1_callback.bind(); } + //auto dtr1() { return m_dtr1_callback.bind(); } + //auto rts1() { return m_rts1_callback.bind(); } + +protected: + virtual void device_add_mconfig(machine_config &config) override; + +private: + required_device m_serial; + + //devcb_write_line m_irq4_callback; + //devcb_write_line m_txd1_callback; + //devcb_write_line m_dtr1_callback; + //devcb_write_line m_rts1_callback; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(PSION_ASIC5_PACK, psion_asic5_pack_device) +DECLARE_DEVICE_TYPE(PSION_ASIC5_PERIPHERAL, psion_asic5_peripheral_device) + +#endif // MAME_MACHINE_PSION_ASIC5_H diff --git a/src/devices/machine/psion_asic9.cpp b/src/devices/machine/psion_asic9.cpp new file mode 100644 index 00000000000..3f78e177dc3 --- /dev/null +++ b/src/devices/machine/psion_asic9.cpp @@ -0,0 +1,1134 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/****************************************************************************** + + Psion ASIC9 + + ASIC9 is a composite chip comprising of a V30H processor, ASIC1, ASIC2 and + general I/O and PSU control logic all on one IC. ASIC9 thus integrates all + the digital logic required to produce a SIBO architecture computer less the + memory onto one chip. ASIC9 has a few additional features such as an extra + free-running clock (FRC) and a codec interface for sound. + + TODO: + - memory protection + - improve RAM configuration for mx machines + - set RTC timer + +******************************************************************************/ + +#include "emu.h" +#include "psion_asic9.h" +#include "cpu/nec/nec.h" +#include "screen.h" + + +#define VERBOSE 0 +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + + +DEFINE_DEVICE_TYPE(PSION_ASIC9, psion_asic9_device, "psion_asic9", "Psion ASIC9") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +psion_asic9_device::psion_asic9_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, PSION_ASIC9, tag, owner, clock) + , device_memory_interface(mconfig, *this) + , device_video_interface(mconfig, *this) + , m_maincpu(*this, "maincpu") + , m_ram(*this, finder_base::DUMMY_TAG) + , m_rom(*this, finder_base::DUMMY_TAG) + , m_ram_config("asic9_ram", ENDIANNESS_LITTLE, 16, 24, 0) + , m_rom_config("asic9_rom", ENDIANNESS_LITTLE, 16, 24, 0) + , m_tick_timer(nullptr) + , m_frc1_timer(nullptr) + , m_frc2_timer(nullptr) + , m_watchdog_timer(nullptr) + , m_rtc_timer(nullptr) + , m_configure_ram_cb(*this) + , m_buz_cb(*this) + , m_col_cb(*this) + , m_port_ab_r(*this) + , m_port_ab_w(*this) + , m_data_r(*this) + , m_data_w(*this) +{ +} + + +void psion_asic9_device::mem_map(address_map &map) +{ + map(0x00000, 0xfffff).rw(FUNC(psion_asic9_device::mem_r), FUNC(psion_asic9_device::mem_w)); +} + +void psion_asic9_device::io_map(address_map &map) +{ + map(0x0000, 0x00ff).rw(FUNC(psion_asic9_device::io_r), FUNC(psion_asic9_device::io_w)); +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void psion_asic9_device::device_add_mconfig(machine_config &config) +{ + V30(config, m_maincpu, DERIVED_CLOCK(1, 1)); + m_maincpu->set_addrmap(AS_PROGRAM, &psion_asic9_device::mem_map); + m_maincpu->set_addrmap(AS_IO, &psion_asic9_device::io_map); + m_maincpu->set_irq_acknowledge_callback(FUNC(psion_asic9_device::inta_cb)); +} + + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +device_memory_interface::space_config_vector psion_asic9_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(AS_A9_RAM, &m_ram_config), + std::make_pair(AS_A9_ROM, &m_rom_config) + }; +} + + +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void psion_asic9_device::device_resolve_objects() +{ + m_buz_cb.resolve_safe(); + m_col_cb.resolve_safe(); + m_port_ab_r.resolve_safe(0); + m_port_ab_w.resolve_safe(); + m_data_r.resolve_all_safe(0x00); + m_data_w.resolve_all_safe(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void psion_asic9_device::device_start() +{ + m_ram_space = &space(AS_A9_RAM); + m_rom_space = &space(AS_A9_ROM); + + switch (m_ram->size()) + { + case 0x010000: case 0x020000: + m_ram_type = 0; + break; + + case 0x040000: case 0x080000: + m_ram_type = 1; + break; + + case 0x100000: case 0x200000: + m_ram_type = 2; + break; + + case 0x400000: case 0x800000: + m_ram_type = 3; + break; + } + + configure_ram(m_ram_type); + configure_rom(); + + m_tick_timer = timer_alloc(FUNC(psion_asic9_device::tick), this); + m_frc1_timer = timer_alloc(FUNC(psion_asic9_device::frc1), this); + 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_busy_timer = timer_alloc(FUNC(psion_asic9_device::busy), this); + + m_a9_control = 0x00; + m_a9_status = 0x00; + + save_item(NAME(m_a9_control)); + save_item(NAME(m_a9_lcd_size)); + save_item(NAME(m_a9_interrupt_status)); + save_item(NAME(m_a9_interrupt_mask)); + save_item(NAME(m_a9_protection_mode)); + save_item(NAME(m_a9_protection_upper)); + save_item(NAME(m_a9_protection_lower)); + save_item(NAME(m_a9_port_ab_ddr)); + save_item(NAME(m_a9_port_c_ddr)); + save_item(NAME(m_a9_port_d_ddr)); + save_item(NAME(m_a9_psel_6000)); + save_item(NAME(m_a9_psel_7000)); + save_item(NAME(m_a9_psel_8000)); + save_item(NAME(m_a9_psel_9000)); + save_item(NAME(m_a9_control_extra)); + save_item(NAME(m_frc1_count)); + save_item(NAME(m_frc1_reload)); + save_item(NAME(m_frc2_count)); + save_item(NAME(m_frc2_reload)); + save_item(NAME(m_watchdog_count)); + save_item(NAME(m_rtc)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void psion_asic9_device::device_reset() +{ + m_tick_timer->adjust(attotime::from_hz(32.768), 0, attotime::from_hz(32.768)); + m_frc1_timer->adjust(attotime::from_hz(512000), 0, attotime::from_hz(512000)); + 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_post = 0x00; + + m_a9_interrupt_status = 0x00; + m_a9_interrupt_mask = 0x00; + + m_frc1_count = 0; + m_frc1_reload = 0; + m_frc2_count = 0; + m_frc2_reload = 0; + m_watchdog_count = 0; + m_a9_protection_mode = false; + m_a9_protection_lower = 0x00; + m_a9_protection_upper = 0x00; + m_a9_port_ab_ddr = 0x00; + m_a9_port_c_ddr = 0x00; + m_a9_port_d_ddr = 0x00; + m_a9_psel_6000 = 0x00; + m_a9_psel_7000 = 0x00; + m_a9_psel_8000 = 0x00; + m_a9_psel_9000 = 0x00; + m_a9_control_extra = 0x00; + m_rtc = time(nullptr) - 946684800; + + //m_a9_status |= 0x2000; // A9MReset + m_a9_status |= 0xe000; // A9MCold + m_a9_serial_control = 0x00; + m_a9_channel_select = 0x00; +} + + +TIMER_CALLBACK_MEMBER(psion_asic9_device::tick) +{ + m_a9_interrupt_status |= 0x02; // Timer + update_interrupts(); +} + +TIMER_CALLBACK_MEMBER(psion_asic9_device::frc1) +{ + switch (--m_frc1_count) + { + case 0x0000: + m_a9_interrupt_status |= 0x40; // A9MFrc1 + update_interrupts(); + break; + + case 0xffff: + if (BIT(m_a9_control, 12)) // A9MFrc1PreScale + m_frc1_count = m_frc1_reload; + break; + } +} + +TIMER_CALLBACK_MEMBER(psion_asic9_device::frc2) +{ + switch (--m_frc2_count) + { + case 0x0000: + m_a9_interrupt_status |= 0x80; // A9MFrc2 + update_interrupts(); + break; + + case 0xffff: + if (BIT(m_a9_control, 14)) // A9MFrc2PreScale + m_frc2_count = m_frc2_reload; + break; + } +} + +TIMER_CALLBACK_MEMBER(psion_asic9_device::watchdog) +{ + m_watchdog_count++; + m_watchdog_count &= 3; + + if (m_watchdog_count == 3) + { + m_a9_status |= 0x0001; // A9MWatchDogNMI + update_interrupts(); + } +} + +TIMER_CALLBACK_MEMBER(psion_asic9_device::rtc) +{ + m_rtc++; +} + +WRITE_LINE_MEMBER(psion_asic9_device::eint_w) +{ + if (state) + m_a9_interrupt_status |= 0x10; // Asic2Int + else + m_a9_interrupt_status &= ~0x10; + + update_interrupts(); +} + +WRITE_LINE_MEMBER(psion_asic9_device::enmi_w) +{ + if (state) + m_a9_control |= 0x0200; // ExternalNmi + else + m_a9_control &= ~0x0200; + + update_interrupts(); +} + + +WRITE_LINE_MEMBER(psion_asic9_device::medchng_w) +{ + if (state) + m_a9_status |= 0x04; // A9MDoorNMI + else + m_a9_status &= ~0x04; + + update_interrupts(); +} + +void psion_asic9_device::update_interrupts() +{ + bool irq = m_a9_interrupt_status & m_a9_interrupt_mask; + bool nmi = m_a9_status & 0x000f; + + m_maincpu->set_input_line(INPUT_LINE_IRQ0, irq ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(INPUT_LINE_NMI, nmi ? ASSERT_LINE : CLEAR_LINE); +} + + +IRQ_CALLBACK_MEMBER(psion_asic9_device::inta_cb) +{ + // IRQ Vector Name Description + // 0 0x78 CSINT CODEC sound interrupt. + // 1 0x79 TINT 32 Hz tick interrupt. + // 2 0x7A SSINT Serial slave interrupt. + // 3 0x7B EINT0 External interrupt input 0. + // 4 0x7C EINT1 External interrupt input 1 (inverted). + // 5 0x7D EINT2 External interrupt input 2 (inverted). + // 6 0x7E FRC1OI FRC1 overflow interrupt. + // 7 0x7F FRC2OI FRC2 overflow interrupt. + uint8_t vector = 0x78; + for (int irq = 0; irq < 8; irq++) + { + if (m_a9_interrupt_status & m_a9_interrupt_mask & (1 << irq)) + { + vector += irq; + break; + } + } + return vector; +} + + +TIMER_CALLBACK_MEMBER(psion_asic9_device::busy) +{ + m_maincpu->set_input_line(NEC_INPUT_LINE_POLL, ASSERT_LINE); +} + + +//************************************************************************** +// RAM/ROM CONFIGURATION +//************************************************************************** + +uint32_t psion_asic9_device::ram_device_size(uint8_t device_type) +{ + uint32_t size = 0; + + switch (device_type & 3) + { + case 0: size = 0x010000; break; // 256KBits + case 1: size = 0x040000; break; // 1MBits + case 2: size = 0x100000; break; // 4MBits + case 3: size = 0x400000; break; // 16MBits + } + return size; +} + +void psion_asic9_device::configure_ram(uint8_t device_type) +{ + uint32_t device_size_actual = ram_device_size(m_ram_type); + uint32_t device_size_test = ram_device_size(device_type); + + m_ram_space->unmap_readwrite(0, 0xffffff); + + for (int i = 0; i < (m_ram->size() / device_size_actual); i++) + { + offs_t addrstart = device_size_test * i; + offs_t addrend = (device_size_test * i) + std::min(device_size_actual, device_size_test) - 1; + offs_t addrmirror = 0xffffff ^ ((device_size_test * 4) - 1); + + if (device_size_actual < device_size_test) + addrmirror ^= (device_size_test - device_size_actual); + + LOG("configure_ram: %d type %d ramsize %06x devsize %06x start %06x end %06x mirror %06x\n", i, device_type, m_ram->size(), device_size_actual, addrstart, addrend, addrmirror); + m_ram_space->install_ram(addrstart, addrend, addrmirror, m_ram->pointer() + (device_size_actual * i)); + } +} + +void psion_asic9_device::configure_rom() +{ + m_rom_space->install_rom(0x800000, 0x800000 + m_rom->bytes() - 1, 0x7fffff ^ (m_rom->bytes() - 1), m_rom->base()); +} + + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +uint8_t psion_asic9_device::col_r() +{ + return m_a9_control_extra & 0x0f; +} + + +bool psion_asic9_device::is_protected(offs_t offset) +{ + //if (m_a9_protection_mode && (offset <= m_a9_protection_lower || offset > m_a9_protection_upper)) + //{ + // LOG("%s is_protected: %05x < %05x <= %05x\n", machine().describe_context(), m_a9_protection_lower, offset, m_a9_protection_upper); + // m_a9_status |= 0x0002; // A9MProtectedModeNMI + // update_interrupts(); + // return true; + //} + return false; +} + +uint16_t psion_asic9_device::mem_r(offs_t offset, uint16_t mem_mask) +{ + uint16_t data = 0xffff; + + offset <<= 1; + + switch (offset & 0xf0000) + { + case 0x00000: case 0x10000: case 0x20000: case 0x30000: case 0x40000: case 0x50000: + data = m_ram_space->read_word(offset, mem_mask); + break; + + case 0x60000: + data = m_ram_space->read_word((m_a9_psel_6000 << 16) | (offset & 0xffff), mem_mask); + break; + + case 0x70000: + data = m_ram_space->read_word((m_a9_psel_7000 << 16) | (offset & 0xffff), mem_mask); + break; + + case 0x80000: + data = m_rom_space->read_word((m_a9_psel_8000 << 16) | (offset & 0xffff), mem_mask); + break; + + case 0x90000: + data = m_rom_space->read_word((m_a9_psel_9000 << 16) | (offset & 0xffff), mem_mask); + break; + + case 0xa0000: case 0xb0000: case 0xc0000: case 0xd0000: case 0xe0000: case 0xf0000: + data = m_rom_space->read_word(0xf00000 | offset, mem_mask); + break; + } + + return data; +} + +void psion_asic9_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + offset <<= 1; + + if (!is_protected(offset)) + { + switch (offset & 0xf0000) + { + case 0x00000: case 0x10000: case 0x20000: case 0x30000: case 0x40000: case 0x50000: + m_ram_space->write_word(offset, data, mem_mask); + break; + + case 0x60000: + m_ram_space->write_word((m_a9_psel_6000 << 16) | (offset & 0xffff), data, mem_mask); + break; + + case 0x70000: + m_ram_space->write_word((m_a9_psel_7000 << 16) | (offset & 0xffff), data, mem_mask); + break; + } + } +} + + +uint16_t psion_asic9_device::io_r(offs_t offset, uint16_t mem_mask) +{ + uint16_t data = 0x00; + + offset <<= 1; + + switch (offset) + { + case 0x00: // A9Index - Not used + LOG("%s io_r: A9Index => %02x\n", machine().describe_context(), data); + break; + + case 0x02: // A9WControl + // b0 A9MDisableClockDivide + // b1 A9MDisableIoWait + // b2 A9MDisableMemWait + // b3-b4 A9MRamDeviceSize + // b5 A9MDisableDMADivide + // b6 A9MArmStandBy + // b7 A9MZeroIsGrayMode + // b8 A9MDoorNMIEnable + // b9 A9MLowBatNMIEnable + // b10 A9MLcdEnable + // b11 A9MSoundEnable + // b12 A9MFrc1PreScale + // b13 A9MFrc1Is512KHzOr1Hz + // b14 A9MFrc2PreScale + // b15 A9MFrc2Is512KHzOr1KHz + data = m_a9_control; // | 0x18; + LOG("%s io_r: A9WControl => %04x\n", machine().describe_context(), data); + break; + + case 0x04: // A9WStatus + // b0 A9MWatchDogNMI + // b1 A9MProtectedModeNMI + // b2 A9MDoorNMI + // b3 A9MLowBatNMI + // b4 A9MDoorSwitch + // b5 A9MMainsPresent + // b6 A9MSlaveClock + // b7 A9MKeyboard + // b8 A9MSlaveDataValid + // b9 A9MSlaveControlFrame + // b10 A9MSlaveOverrun + // b11 A9MFifoFull + // b12 A9MNoBattery + // b13 A9MReset + // b14 A9MPowerFail + // b15 A9MCold + data = m_a9_status; + if (!machine().side_effects_disabled()) + { + m_a9_status &= ~0x2000; // clear A9MReset + } + LOG("%s io_r: A9WStatus => %04x\n", machine().describe_context(), data); + break; + + case 0x06: // A9BInterruptStatus + if (ACCESSING_BITS_0_7) + { + data = m_a9_interrupt_status; + LOG("%s io_r: A1InterruptStatus => %02x\n", machine().describe_context(), data); + } + break; + + case 0x08: // A9BInterruptMask + if (ACCESSING_BITS_0_7) + { + data = m_a9_interrupt_mask; + LOG("%s io_r: A9BInterruptMask => %02x\n", machine().describe_context(), data); + } + break; + + case 0x12: // A9WFrc1Data + data = m_frc1_count; + LOG("%s io_r: A9WFrc1Data => %04x\n", machine().describe_context(), data); + break; + + case 0x14: // A9BProtectionOff + if (ACCESSING_BITS_0_7) + { + //LOG("%s io_r: A9BProtectionOff => %02x\n", machine().describe_context(), data); + m_a9_protection_mode = false; + } + break; + + case 0x1a: // A9BSoundData + if (ACCESSING_BITS_0_7) + { + LOG("%s io_r: A9BSoundData => %02x\n", machine().describe_context(), data); + } + break; + + case 0x1e: // A9WFrc2Data + data = m_frc2_count; + LOG("%s io_r: A9WFrc2Data => %04x\n", machine().describe_context(), data); + break; + + case 0x20: // A9WPortABData + data = m_port_ab_r() & ~m_a9_port_ab_ddr; + LOG("%s io_r: A9WPortABData => %04x\n", machine().describe_context(), data); + break; + + case 0x22: // A9WPortABDDR + if (ACCESSING_BITS_0_7) + { + 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; + LOG("%s io_r: A9WPortBDDR => %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x24: // A9WPortCDData + if (ACCESSING_BITS_0_7) + { + data = 0x00; + LOG("%s io_r: A9WPortCData => %02x\n", machine().describe_context(), data); + } + if (ACCESSING_BITS_8_15) + { + data = 0x00 << 8; + LOG("%s io_r: A9WPortDData => %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x26: // A9BPortCDDDR + if (ACCESSING_BITS_0_7) + { + data |= m_a9_port_c_ddr; + LOG("%s io_r: A9BPortCDDR => %04x\n", machine().describe_context(), data); + } + if (ACCESSING_BITS_8_15) + { + data |= m_a9_port_d_ddr << 8; + LOG("%s io_r: A9WPortDDDR <= %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x28: // A9BPageSelect6000 + if (ACCESSING_BITS_0_7) + { + data |= m_a9_psel_6000; + LOG("%s io_r: A9BPageSelect6000 => %02x\n", machine().describe_context(), data); + } + if (ACCESSING_BITS_8_15) + { + data |= m_a9_psel_7000 << 8; + LOG("%s io_r: A9BPageSelect7000 => %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x2a: // A9BPageSelect8000 + if (ACCESSING_BITS_0_7) + { + data |= m_a9_psel_8000; + //LOG("%s io_r: A9BPageSelect8000 => %02x\n", machine().describe_context(), data); + } + if (ACCESSING_BITS_8_15) + { + data |= m_a9_psel_9000 << 8; + //LOG("%s io_r: A9BPageSelect9000 => %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x2c: // A9WControlExtra + data = m_a9_control_extra; + LOG("%s io_r: A9WControlExtra => %04x\n", machine().describe_context(), data); + break; + + case 0x2e: // A9WPumpControl + LOG("%s io_r: A9WPumpControl <= %04x\n", machine().describe_context(), data); + break; + + case 0x80: // A9WRtcLSW + data = m_rtc & 0x0000ffff; + //LOG("%s io_r: A9WRtcLSW <= %04x\n", machine().describe_context(), data); + break; + + case 0x82: // A9WRtcMSW + data = (m_rtc & 0xffff0000) >> 16; + //LOG("%s io_r: A9WRtcMSW <= %04x\n", machine().describe_context(), data); + break; + + case 0x88: // A9BSlaveData + LOG("%s io_r: A9BSlaveData <= %02x\n", machine().describe_context(), data); + break; + + case 0x8a: // A9BSerialData + data = m_a9_serial_data; + if ((m_a9_serial_control & 0x10) == 0x10) + m_a9_serial_data = receive_frame(); + LOG("%s io_r: A9BSerialData => %02x\n", machine().describe_context(), data); + break; + + case 0x8e: // A9BChannelSelect + data = m_a9_channel_select; + break; + + default: + logerror("%s io_r: Unhandled register %02x => %04x\n", machine().describe_context(), offset, data); + break; + } + return data; +} + +void psion_asic9_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + offset <<= 1; + + switch (offset) + { + case 0x00: // Post + if (m_post != data) + { + switch (data) + { + case 0x10: LOG("%s io_w: Post <= %02x ROM Test\n", machine().describe_context(), data); break; + case 0x20: LOG("%s io_w: Post <= %02x System RAM Test\n", machine().describe_context(), data); break; + case 0x30: LOG("%s io_w: Post <= %02x Video RAM Test\n", machine().describe_context(), data); break; + case 0xf0: LOG("%s io_w: Post <= %02x Complete\n", machine().describe_context(), data); break; + default: LOG("%s io_w: Post <= %02x Unknown\n", machine().describe_context(), data); break; + } + m_post = data; + } + break; + + case 0x02: // A9WControl + // b0 A9MDisableClockDivide + // b1 A9MDisableIoWait + // b2 A9MDisableMemWait + // b3-b4 A9MRamDeviceSize + // b5 A9MDisableDMADivide + // b6 A9MArmStandBy + // b7 A9MZeroIsGrayMode + // b8 A9MDoorNMIEnable + // b9 A9MLowBatNMIEnable + // b10 A9MLcdEnable + // b11 A9MSoundEnable + // b12 A9MFrc1PreScale + // b13 A9MFrc1Is512KHzOr1Hz + // b14 A9MFrc2PreScale + // b15 A9MFrc2Is512KHzOr1KHz + LOG("%s io_w: A9WControl <= %04x, RamDeviceSize %s, Frc1 %s%s, Frc2 %s%s\n", machine().describe_context(), data, + BIT(data, 3,2) == 0 ? "256KBits" : (BIT(data, 3,2) == 1 ? "1MBits" : (BIT(data, 3,2) == 2 ? "4MBits" : "16MBits")), + BIT(data, 13) ? "512KHz" : "1Hz", BIT(data, 12) ? " PreScale" : "", + BIT(data, 15) ? "512KHz" : "1024Hz", BIT(data, 14) ? " PreScale" : ""); + + if (BIT(data, 3, 2) != BIT(m_a9_control, 3, 2)) + { + configure_ram(BIT(data, 3, 2)); + } + if (BIT(data, 13) != BIT(m_a9_control, 13)) + { + if (data & 0x2000) + m_frc1_timer->adjust(attotime::zero, 0, attotime::from_hz(512000)); + else + m_frc1_timer->adjust(attotime::zero, 0, attotime::from_hz(1)); + } + if (BIT(data, 15) != BIT(m_a9_control, 15)) + { + if (data & 0x8000) + m_frc2_timer->adjust(attotime::zero, 0, attotime::from_hz(512000)); + else + m_frc2_timer->adjust(attotime::zero, 0, attotime::from_hz(1024)); + } + m_a9_control = data; + break; + + case 0x04: // A9WLcdSize + // b0-b10 A9MLcdNumberOfPixels - (end of frame address / 16) - 1 + // b11-b15 A9MLcdLineLength - (number of pixels per line / 32) - 1 + LOG("%s io_w: A9WLcdSize <= %04x, Pixels in line %d, Total pixels in display %d\n", machine().describe_context(), data, (BIT(data, 11, 5) + 1) * 32, (BIT(data, 0, 11) + 1) * 128); + m_a9_lcd_size = data; + break; + + case 0x06: // A9WLcdControl + // b0-b4 LcdPixelRate - 3 + // b5-b9 LcdACLineRate - 13 + // b10-b11 LcdMode - 3 (Dual Screen mode) + LOG("%s io_w: A9WLcdControl <= %04x, Mode %d %s Page\n", machine().describe_context(), data, BIT(data, 10,2), BIT(data, 10,2) == 3 ? "Dual" : "Single"); + break; + + case 0x08: // A9BInterruptMask + if (ACCESSING_BITS_0_7) + { + // b0 A9MSound + // b1 A9MTimer + // b2 A9MSlave + // b3 A9MExpIntC + // b4 A9MExpIntA + // b5 A9MExpIntB + // b6 A9MFrc1 + // b7 A9MFrc2 + LOG("%s io_w: A9BInterruptMask <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_interrupt_mask = data & 0xff; + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9BNmiClear <= %02x\n", machine().describe_context(), data >> 8); + m_a9_status &= 0xfff0; + } + update_interrupts(); + break; + + case 0x0a: // A9BNonSpecificEoi + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9BNonSpecificEoi <= %02x\n", machine().describe_context(), data & 0xff); + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9BStartFlagClear <= %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x0c: // A9BTimerEoiW + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9BTimerEoi <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_interrupt_status &= ~0x02; // Timer + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9BSerialSlaveEoi <= %02x\n", machine().describe_context(), data >> 8); + m_a9_interrupt_status &= ~0x04; // SerialSlave + } + update_interrupts(); + break; + + case 0x0e: // A9Frc1Eoi + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9Frc1Eoi <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_interrupt_status &= ~0x40; // Frc1Expired + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9Frc2Eoi <= %02x\n", machine().describe_context(), data >> 8); + m_a9_interrupt_status &= ~0x80; // Frc2Expired + } + update_interrupts(); + break; + + case 0x10: // A9WResetWatchDog + //LOG("%s io_w: A9WResetWatchDog <= %04x\n", machine().describe_context(), data); + m_watchdog_count = 0; + break; + + case 0x12: // A9WFrc1Data + LOG("%s io_w: A9WFrc1Data <= %04x\n", machine().describe_context(), data); + m_frc1_reload = data; + m_frc1_count = data; + break; + + case 0x14: // A9BProtectionOn + if (ACCESSING_BITS_0_7) + { + //LOG("%s io_w: A9BProtectionOn <= %02x\n", machine().describe_context(), data); + m_a9_protection_mode = true; + } + if (ACCESSING_BITS_8_15) + { + //LOG("%s io_w: A9BProtectionOff <= %02x\n", machine().describe_context(), data); + m_a9_protection_mode = false; + } + break; + + case 0x16: // A9WProtectionUpper + //LOG("%s io_w: A9WProtectionUpper <= %04x\n", machine().describe_context(), data); + m_a9_protection_upper = (data << 4) | 0x0f; + break; + + case 0x18: // A9WProtectionLower + //LOG("%s io_w: A9WProtectionLower <= %04x\n", machine().describe_context(), data); + m_a9_protection_lower = data << 4; + break; + + case 0x1a: // A9BSoundData + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9BSoundData <= %04x\n", machine().describe_context(), data); + } + break; + + case 0x1c: // A9BSoundEoi + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9BSoundEoi <= %02x\n", machine().describe_context(), data); + m_a9_interrupt_status &= ~0x01; // Sound + update_interrupts(); + } + break; + + case 0x1e: // A9WFrc2Data + LOG("%s io_w: A9WFrc2Data <= %04x\n", machine().describe_context(), data); + m_frc2_reload = data; + m_frc2_count = data; + break; + + case 0x20: // A9WPortABData + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9WPortAData <= %02x\n", machine().describe_context(), data & 0xff); + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9WPortBData <= %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x22: // A9WPortABDDR + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9WPortADDR <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_port_ab_ddr = (m_a9_port_ab_ddr & 0xff00) | data; + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9WPortBDDR <= %02x\n", machine().describe_context(), data >> 8); + m_a9_port_ab_ddr = (m_a9_port_ab_ddr & 0x00ff) | (data << 8); + } + break; + + case 0x24: // A9WPortCDData + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9WPortCData <= %02x\n", machine().describe_context(), data & 0xff); + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9WPortDData <= %02x\n", machine().describe_context(), data >> 8); + } + break; + + case 0x26: // A9BPortCDDDR + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9WPortCDDR <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_port_c_ddr = data & 0xff; + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9WPortDDDR <= %02x\n", machine().describe_context(), data >> 8); + m_a9_port_d_ddr = data >> 8; + } + break; + + case 0x28: // A9BPageSelect6000 + if (ACCESSING_BITS_0_7) + { + LOG("%s io_w: A9BPageSelect6000 <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_psel_6000 = data & 0xff; + } + if (ACCESSING_BITS_8_15) + { + LOG("%s io_w: A9BPageSelect7000 <= %02x\n", machine().describe_context(), data >> 8); + m_a9_psel_7000 = data >> 8; + } + break; + + case 0x2a: // A9BPageSelect8000 + if (ACCESSING_BITS_0_7) + { + //LOG("%s io_w: A9BPageSelect8000 <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_psel_8000 = data & 0xff; + } + if (ACCESSING_BITS_8_15) + { + //LOG("%s io_w: A9BPageSelect9000 <= %02x\n", machine().describe_context(), data >> 8); + m_a9_psel_9000 = data >> 8; + } + break; + + case 0x2c: // A9WControlExtra + // b0-b3 A9MKeyCol + // b4 A9MBuzzTog + // b5 A9MBuzzFromFrc1OrTog + // b6 A9MExonDisable + // b7 A9MSoundDir + // b8 A9MClockEnable1 + // b9 A9MClockEnable2 + // b10 A9MClockEnable3 + // b11 A9MClockEnable4 + // b12 A9MClockEnable5 + // b13-b14 A9MClkDiv + // b15 A9MSlaveIntEnable + LOG("%s io_w: A9WControlExtra <= %04x\n", machine().describe_context(), data); + m_a9_control_extra = data; + + // enable keyboard COLs + switch (data & 0xf) + { + case 0x0: m_col_cb(0xff); break; + case 0x8: m_col_cb(0x01); break; + case 0x9: m_col_cb(0x02); break; + case 0xa: m_col_cb(0x04); break; + case 0xb: m_col_cb(0x08); break; + case 0xc: m_col_cb(0x10); break; + case 0xd: m_col_cb(0x20); break; + case 0xe: m_col_cb(0x40); break; + case 0xf: m_col_cb(0x80); break; + default: m_col_cb(0x00); break; + } + + if (!BIT(data, 5)) + { + m_buz_cb(BIT(data, 4)); + } + break; + + case 0x2e: // A9WPumpControl + LOG("%s io_w: A9WPumpControl <= %04x\n", machine().describe_context(), data); + break; + + case 0x80: // A9WRtcLSW + //LOG("%s io_w: A9WRtcLSW <= %04x\n", machine().describe_context(), data); + m_rtc = (m_rtc & 0xffff0000) | data; + break; + + case 0x82: // A9WRtcMSW + //LOG("%s io_w: A9WRtcMSW <= %04x\n", machine().describe_context(), data); + m_rtc = (m_rtc & 0x0000ffff) | (data << 16); + break; + + case 0x84: // A9WNullFrame + LOG("%s io_w: A9WNullFrame <= %02x\n", machine().describe_context(), data); + transmit_frame(NULL_FRAME); + break; + + case 0x8a: // A9BSerialData + LOG("%s io_w: A9BSerialData <= %02x\n", machine().describe_context(), data & 0xff); + if ((m_a9_serial_control & 0xc0) == 0x80) + transmit_frame(DATA_FRAME | (data & 0xff)); + break; + + case 0x8c: // A9BSerialControl - Serial channel write control register + // WriteSingle 10000000b; ReadSingle 11000000b + // WriteMulti 10010000b; ReadMulti 11010000b + // Reset 00000000b; Select 01000000b + // Asic4Id 001h; Asic5PackId 002h + // Asic5NormalId 003h; Asic6Id 004h + // Asic8Id 005h; Asic2SlaveId 01fh + LOG("%s io_w: A2SerialControl <= %02x\n", machine().describe_context(), data & 0xff); + m_a9_serial_control = data & 0xff; + transmit_frame(CONTROL_FRAME | m_a9_serial_control); + + if ((m_a9_serial_control & 0x40) == 0x40) + m_a9_serial_data = receive_frame(); + break; + + case 0x8e: // A9BChannelSelect - Serial channel select register + // b0 Pack1Enable - 1 to select pack 1 + // b1 Pack2Enable - 1 to select pack 2 + // b2 Pack3Enable - 1 to select pack 3 + // b3 Pack4Enable - 1 to select pack 4 + // b4 Pack5Enable - 1 to select pack 5 + // b5-b6 SerialClockRate - 0 Medium, 1 Special, 2 Slow, 3 Fast + // b7 MultiplexEnable - 1 to loop slave channel to pack channel + LOG("%s io_w: A9BChannelSelect <= %02x Channels %c %c %c %c %c\n", machine().describe_context(), data & 0xff, + BIT(data, 0) ? '0' : ' ', + BIT(data, 1) ? '1' : ' ', + BIT(data, 2) ? '2' : ' ', + BIT(data, 3) ? '3' : ' ', + BIT(data, 4) ? '4' : ' '); + m_a9_channel_select = data & 0xff; + break; + + default: + logerror("%s io_w: Unhandled register %02x <= %04x\n", machine().describe_context(), offset, data); + break; + } +} + + +//------------------------------------------------- +// SIBO Serial Protocol Controller +//------------------------------------------------- + +bool psion_asic9_device::channel_active(int channel) +{ + switch (channel) + { + case 0: case 1: case 2: case 3: case 4: + return BIT(m_a9_channel_select, channel); + } + return false; +} + +void psion_asic9_device::transmit_frame(uint16_t data) +{ + m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2)); + m_maincpu->set_input_line(NEC_INPUT_LINE_POLL, CLEAR_LINE); + + for (int ch = 0; ch < 8; ch++) + { + if (channel_active(ch)) + { + LOG("%s Channel %d Transmit %s frame %02x\n", machine().describe_context(), ch, (data & DATA_FRAME) ? "Data" : (data & CONTROL_FRAME) ? "Control" : "Null", data & 0xff); + m_data_w[ch](data); + } + } +} + +uint8_t psion_asic9_device::receive_frame() +{ + uint8_t data = 0x00; + + m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2)); + m_maincpu->set_input_line(NEC_INPUT_LINE_POLL, CLEAR_LINE); + + for (int ch = 0; ch < 8; ch++) + { + if (channel_active(ch)) + { + data |= m_data_r[ch](); + LOG("%s Channel %d Receive Data frame %02x\n", machine().describe_context(), ch, data); + } + } + + return data; +} + + +//------------------------------------------------- +// LCD Controller +//------------------------------------------------- + +uint32_t psion_asic9_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (m_a9_control & 0x0400) // LCD enable bit + { + pen_t const *const pens = screen.palette().pens(); + + int const width = (BIT(m_a9_lcd_size, 11, 5) + 1) * 32; + uint16_t const size = (BIT(m_a9_lcd_size, 0, 11) + 1) * 16; + + for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++) + { + for (int x = screen.visible_area().min_x; x <= (screen.visible_area().max_x / 8); x++) + { + uint8_t const black = m_ram_space->read_byte(0x0400 + y * (width / 8) + x); + uint8_t const grey = m_ram_space->read_byte(0x0400 + size + y * (width / 8) + x); + uint16_t *p = &bitmap.pix(y, x << 3); + for (int i = 0; i < 8; i++) + *p++ = BIT(black, i) ? pens[1] : (BIT(grey, i) ? pens[2] : pens[0]); + } + } + } + else + { + bitmap.fill(0, cliprect); + } + return 0; +} diff --git a/src/devices/machine/psion_asic9.h b/src/devices/machine/psion_asic9.h new file mode 100644 index 00000000000..142ab33c7c9 --- /dev/null +++ b/src/devices/machine/psion_asic9.h @@ -0,0 +1,155 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/****************************************************************************** + + Psion ASIC9 + +******************************************************************************/ + +#ifndef MAME_MACHINE_PSION_ASIC9_H +#define MAME_MACHINE_PSION_ASIC9_H + +#pragma once + +#include "machine/ram.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> psion_asic9_device + +class psion_asic9_device : public device_t, + public device_memory_interface, + public device_video_interface +{ +public: + psion_asic9_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template void set_ram_rom(T &&ram_tag, U &&rom_tag) { m_ram.set_tag(std::forward(ram_tag)); m_rom.set_tag(std::forward(rom_tag)); } + + // callbacks + auto buz_cb() { return m_buz_cb.bind(); } + 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(); } + + 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(); } + + 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); + void mem_w(offs_t offset, uint16_t data, uint16_t mem_mask); + + uint8_t col_r(); + + IRQ_CALLBACK_MEMBER(inta_cb); + + DECLARE_WRITE_LINE_MEMBER(eint_w); + DECLARE_WRITE_LINE_MEMBER(enmi_w); + DECLARE_WRITE_LINE_MEMBER(medchng_w); + + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + + virtual space_config_vector memory_space_config() const override; + +private: + required_device m_maincpu; + required_device m_ram; + required_memory_region m_rom; + + void mem_map(address_map &map); + void io_map(address_map &map); + + static constexpr int AS_A9_RAM = AS_OPCODES + 1; + static constexpr int AS_A9_ROM = AS_OPCODES + 2; + + const address_space_config m_ram_config; + const address_space_config m_rom_config; + + address_space *m_ram_space; + address_space *m_rom_space; + + emu_timer *m_tick_timer; + emu_timer *m_frc1_timer; + emu_timer *m_frc2_timer; + emu_timer *m_watchdog_timer; + emu_timer *m_rtc_timer; + + TIMER_CALLBACK_MEMBER(tick); + TIMER_CALLBACK_MEMBER(frc1); + TIMER_CALLBACK_MEMBER(frc2); + TIMER_CALLBACK_MEMBER(watchdog); + TIMER_CALLBACK_MEMBER(rtc); + + void update_interrupts(); + bool is_protected(offs_t offset); + + uint8_t m_ram_type; + uint32_t ram_device_size(uint8_t device_type); + void configure_ram(uint8_t device_type = 0); + void configure_rom(); + + uint8_t m_post; + uint16_t m_a9_control; + uint16_t m_a9_status; + uint16_t m_a9_lcd_size; + uint8_t m_a9_interrupt_status; + uint8_t m_a9_interrupt_mask; + uint16_t m_frc1_count; + uint16_t m_frc1_reload; + uint16_t m_frc2_count; + uint16_t m_frc2_reload; + uint8_t m_watchdog_count; + bool m_a9_protection_mode; + uint16_t m_a9_protection_upper; + uint16_t m_a9_protection_lower; + uint8_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; + uint8_t m_a9_psel_7000; + uint8_t m_a9_psel_8000; + uint8_t m_a9_psel_9000; + uint16_t m_a9_control_extra; + uint32_t m_rtc; + + uint8_t m_a9_serial_data; + uint8_t m_a9_serial_control; + uint8_t m_a9_channel_select; + + devcb_write8 m_configure_ram_cb; + devcb_write_line m_buz_cb; + devcb_write8 m_col_cb; + devcb_read16 m_port_ab_r; + devcb_write16 m_port_ab_w; + + devcb_read8::array<8> m_data_r; + devcb_write16::array<8> m_data_w; + + emu_timer *m_busy_timer; + + TIMER_CALLBACK_MEMBER(busy); + + bool channel_active(int channel); + void transmit_frame(uint16_t data); + uint8_t receive_frame(); + + static constexpr uint16_t NULL_FRAME = 0x000; + static constexpr uint16_t CONTROL_FRAME = 0x100; + static constexpr uint16_t DATA_FRAME = 0x200; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(PSION_ASIC9, psion_asic9_device) + +#endif // MAME_MACHINE_PSION_ASIC9_H diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp index 8367a55cfb4..18190ddda56 100644 --- a/src/emu/xtal.cpp +++ b/src/emu/xtal.cpp @@ -144,6 +144,7 @@ const double XTAL::known_xtals[] = { 7'159'090, /* 7.15909_MHz_XTAL Blood Bros (2x NTSC subcarrier) */ 7'200'000, /* 7.2_MHz_XTAL Novag Constellation (later models, with /2 divider), Kawai K1 keyscan IC */ 7'372'800, /* 7.3728_MHz_XTAL - */ + 7'680'000, /* 7.68_MHz_XTAL Psion Series 3 */ 7'864'300, /* 7.8643_MHz_XTAL Used on InterFlip games as video clock */ 7'987'000, /* 7.987_MHz_XTAL PC9801-86 YM2608 clock */ 7'995'500, /* 7.9955_MHz_XTAL Used on Electronic Devices Italy Galaxy Gunners sound board */ diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 09fe053dcd7..0f2e5e5b354 100755 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -37602,9 +37602,24 @@ psionp350 // psionp464 // psionxp // +@source:psion/psion3a.cpp +pocketbk2 // 1994 Acorn Pocket Book II +psion3a // 1993 Psion Series 3a +psion3a2 // 1995 Psion Series 3a +psion3a2_de // 1995 Psion Series 3a (German) +psion3c // 1996 Psion Series 3c +psion3mx // 1998 Psion Series 3mx + @source:psion/psion5.cpp psion5mx // +@source:psion/siena.cpp +siena // 1996 Psion Siena + +@source:psion/workabout.cpp +psionwa // 1995 Psion Workabout +psionwamx // 1998 Psion Workabout mx + @source:quantel/dpb7000.cpp dpb7000 // diff --git a/src/mame/psion/psion3a.cpp b/src/mame/psion/psion3a.cpp new file mode 100644 index 00000000000..71ad5126654 --- /dev/null +++ b/src/mame/psion/psion3a.cpp @@ -0,0 +1,396 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/****************************************************************************** + + Psion Series 3a/3c/3mx + + TODO: + - battery backed RAM + - sound devices + - serial ports + - fix RAM detection for 3mx + +******************************************************************************/ + +#include "emu.h" +#include "machine/psion_asic9.h" +#include "machine/ram.h" +#include "sound/spkrdev.h" +//#include "bus/psion/exp/slot.h" +#include "psion_ssd.h" + +#include "emupal.h" +#include "screen.h" +#include "softlist_dev.h" +#include "speaker.h" +#include "utf8.h" + + +namespace { + +class psion3a_state : public driver_device +{ +public: + psion3a_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_asic9(*this, "asic9") + , m_ram(*this, "ram") + , m_palette(*this, "palette") + , m_keyboard(*this, "COL%u", 0U) + , m_speaker(*this, "speaker") + , m_ssd(*this, "ssd%u", 1U) + //, m_exp(*this, "exp") + { } + + void psion3a(machine_config &config); + void psion3a2(machine_config &config); + void psion3c(machine_config &config); + void psion3mx(machine_config &config); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + +private: + required_device m_asic9; + required_device m_ram; + required_device m_palette; + required_ioport_array<8> m_keyboard; + required_device m_speaker; + required_device_array m_ssd; + //required_device m_exp; + + void palette_init(palette_device &palette); + + uint16_t kbd_r(); + + uint8_t m_key_col = 0; +}; + + +void psion3a_state::machine_start() +{ +} + +void psion3a_state::machine_reset() +{ +} + + +static INPUT_PORTS_START( psion3a ) + PORT_START("COL0") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("Enter") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME(UTF8_RIGHT" End") + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(0x09) PORT_NAME("Tab") + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME(UTF8_LEFT" Home") + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME(UTF8_DOWN" Pg Dn") + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("Psion") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("Sheet") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("Time") + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("Data") + + PORT_START("COL1") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR(';') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('=') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_CHAR(']') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('*') PORT_CHAR(':') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (L)") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("Calc") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("Agenda") + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("System") + + PORT_START("COL2") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x08) PORT_NAME("Delete") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('?') PORT_CHAR('}') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_CHAR('[') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Control") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("World") + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("Word") + + PORT_START("COL3") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_NAME("Help Dial") + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_CHAR('{') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (R)") + + PORT_START("COL4") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('~') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CHAR('\'') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_NAME("Caps") + + PORT_START("COL5") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(0xa3) PORT_CHAR('\\') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) PORT_NAME("Menu") + + PORT_START("COL6") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + + PORT_START("COL7") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_NAME("1 ! Off") + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_CHAR('#') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') PORT_CHAR('@') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME(UTF8_UP" Pg Up") + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_NAME("Esc On") +INPUT_PORTS_END + + +static INPUT_PORTS_START( psion3a_de ) + PORT_INCLUDE(psion3a) + + PORT_MODIFY("COL0") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME(UTF8_RIGHT" Ende") + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME(UTF8_LEFT" Pos1") + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME(UTF8_DOWN" Bild Dn") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("Tabelle") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("Uhr") + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("Daten") + + PORT_MODIFY("COL1") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR(0xdf) + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('<') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('=') PORT_CHAR('}') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('*') PORT_CHAR('>') + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("Rechner") + + PORT_MODIFY("COL2") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x08) PORT_NAME("Entf") + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') PORT_CHAR('[') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') PORT_CHAR(']') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Strg") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("Welt") + + PORT_MODIFY("COL3") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_NAME("Hilfe Wahl") + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('?') PORT_CHAR('{') + + PORT_MODIFY("COL4") + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('@') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CHAR('\'') + + PORT_MODIFY("COL5") + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(0xa7) PORT_CHAR('\\') + + PORT_MODIFY("COL6") + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('y') PORT_CHAR('Y') + + PORT_MODIFY("COL7") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_NAME("1 ! Aus") + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') PORT_CHAR(0xba) + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME(UTF8_UP" Bild Up") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_NAME("Esc Ein") +INPUT_PORTS_END + + +static INPUT_PORTS_START( psion3c ) + PORT_INCLUDE(psion3a) + + PORT_MODIFY("COL2") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) PORT_NAME("Jotter") +INPUT_PORTS_END + + +//static INPUT_PORTS_START( psion3c_de ) +// PORT_INCLUDE(psion3a_de) +// +// PORT_MODIFY("COL2") +// PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9)) PORT_NAME("Notiz") +//INPUT_PORTS_END + + +static INPUT_PORTS_START( pocketbk2 ) + PORT_INCLUDE(psion3a) + + PORT_MODIFY("COL0") + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("Acorn") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("Abacus") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("Time") + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("Cards") + + PORT_MODIFY("COL1") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("Calc") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("Schedule") + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("Desktop") + + PORT_MODIFY("COL2") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("World") + PORT_BIT(0x400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("Write") +INPUT_PORTS_END + + +uint16_t psion3a_state::kbd_r() +{ + uint16_t data = 0x00; + + for (int i = 0; i < 8; i++) + { + if (BIT(m_key_col, i)) + data |= m_keyboard[i]->read(); + } + + return data; +} + + +void psion3a_state::palette_init(palette_device &palette) +{ + palette.set_pen_color(0, rgb_t(190, 220, 190)); + palette.set_pen_color(1, rgb_t(130, 130, 110)); + palette.set_pen_color(2, rgb_t(190, 210, 180)); +} + + +void psion3a_state::psion3a(machine_config &config) +{ + PSION_ASIC9(config, m_asic9, 7.68_MHz_XTAL); // V30H + m_asic9->set_ram_rom("ram", "rom"); + m_asic9->port_ab_r().set(FUNC(psion3a_state::kbd_r)); + m_asic9->buz_cb().set(m_speaker, FUNC(speaker_sound_device::level_w)); + //m_asic9->buzvol_cb().set([this](int state) { m_speaker->set_output_gain(ALL_OUTPUTS, state ? 1.0 : 0.25); }); + m_asic9->col_cb().set([this](uint8_t data) { m_key_col = data; }); + m_asic9->data_r<0>().set(m_ssd[0], FUNC(psion_ssd_device::data_r)); // SSD Pack 1 + m_asic9->data_w<0>().set(m_ssd[0], FUNC(psion_ssd_device::data_w)); + m_asic9->data_r<1>().set(m_ssd[1], FUNC(psion_ssd_device::data_r)); // SSD Pack 2 + m_asic9->data_w<1>().set(m_ssd[1], FUNC(psion_ssd_device::data_w)); + //m_asic9->data_r<4>().set(m_exp, FUNC(psion_exp_slot_device::data_r)); // Expansion port + //m_asic9->data_w<4>().set(m_exp, FUNC(psion_exp_slot_device::data_w)); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); + screen.set_size(480, 160); + screen.set_visarea_full(); + screen.set_refresh_hz(66); + screen.set_screen_update(m_asic9, FUNC(psion_asic9_device::screen_update)); + screen.set_palette(m_palette); + PALETTE(config, "palette", FUNC(psion3a_state::palette_init), 3); + + // TODO: M7542 + + SPEAKER(config, "mono").front_center(); + SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00); // Piezo buzzer + + RAM(config, m_ram).set_default_size("512K").set_extra_options("256K"); + + PSION_SSD(config, m_ssd[0]); + m_ssd[0]->door_cb().set(m_asic9, FUNC(psion_asic9_device::medchng_w)); + PSION_SSD(config, m_ssd[1]); + m_ssd[1]->door_cb().set(m_asic9, FUNC(psion_asic9_device::medchng_w)); + + //PSION_EXP_SLOT(config, m_exp, psion_exp_devices, nullptr); + + SOFTWARE_LIST(config, "ssd_list").set_original("psion_ssd").set_filter("S3,S3A"); +} + +void psion3a_state::psion3a2(machine_config &config) +{ + psion3a(config); + + m_ram->set_default_size("2M").set_extra_options("1M"); +} + +void psion3a_state::psion3c(machine_config &config) +{ + psion3a(config); + + m_ram->set_default_size("2M").set_extra_options("1M"); + + // TODO: M7702 + + // TODO: add Honda port +} + +void psion3a_state::psion3mx(machine_config &config) +{ + psion3a(config); + + m_asic9->set_clock(3.6864_MHz_XTAL * 15 / 2); // V30MX + + m_ram->set_default_size("2M").set_extra_options(""); + + // TODO: M7702 + + // TODO: add Honda port +} + + +ROM_START(psion3a) + ROM_REGION16_LE(0x100000, "rom", 0) + ROM_SYSTEM_BIOS(0, "322f", "V3.22F/ENG") + ROMX_LOAD("s3a_v3.22f_eng.bin", 0x000000, 0x100000, CRC(fafa3820) SHA1(c1a320b43280cfdb74fc1cb1363fca88dd187487), ROM_BIOS(0)) +ROM_END + +ROM_START(psion3a2) + ROM_REGION16_LE(0x200000, "rom", 0) + ROM_SYSTEM_BIOS(0, "340f", "V3.40F/ENG") + ROMX_LOAD("s3a_v3.40f_eng.bin", 0x000000, 0x200000, CRC(f0adf12c) SHA1(3eb4e7f1fc5611a4d6e65d27d336969ebae94395), ROM_BIOS(0)) +ROM_END + +ROM_START(psion3a2_de) + ROM_REGION16_LE(0x200000, "rom", 0) + ROM_SYSTEM_BIOS(0, "341f", "V3.41F/DEU") + ROMX_LOAD("s3a_v3.41f_eng.bin", 0x000000, 0x200000, CRC(1f21cb0a) SHA1(fbb9c3356cf8b1d89b8cf50fc12175568c74ce3e), ROM_BIOS(0)) +ROM_END + +ROM_START(psion3c) + ROM_REGION16_LE(0x200000, "rom", 0) + ROM_SYSTEM_BIOS(0, "520f", "V5.20F/ENG") + ROMX_LOAD("oak_v5.20f_eng.bin", 0x000000, 0x200000, CRC(d8e672ca) SHA1(23e7570ddbecbfd50953ce6a6b7ead7128814402), ROM_BIOS(0)) +ROM_END + +ROM_START(psion3mx) + ROM_REGION16_LE(0x200000, "rom", 0) + ROM_SYSTEM_BIOS(0, "616f", "V6.16F/ENG") + ROMX_LOAD("maple_v6.16f_uk.bin", 0x000000, 0x200000, CRC(10011d9d) SHA1(8c657414513ed57ccf6beddc65dca1fe5ab600fb), ROM_BIOS(0)) +ROM_END + +ROM_START(pocketbk2) + ROM_REGION16_LE(0x200000, "rom", 0) + ROM_SYSTEM_BIOS(0, "130f", "V1.30F/ACN") + ROMX_LOAD("pb2_v1.30f_acn.bin", 0x000000, 0x200000, CRC(d7ba3a50) SHA1(2d29a7ac5ec4d6bf63bd7d93cc3763e0f9763136), ROM_BIOS(0)) +ROM_END + +} // anonymous namespace + + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1993, psion3a, 0, 0, psion3a, psion3a, psion3a_state, empty_init, "Psion", "Series 3a", MACHINE_NOT_WORKING ) +COMP( 1994, pocketbk2, psion3a, 0, psion3a, pocketbk2, psion3a_state, empty_init, "Acorn Computers", "Pocket Book II", MACHINE_NOT_WORKING ) +COMP( 1995, psion3a2, psion3a, 0, psion3a2, psion3a, psion3a_state, empty_init, "Psion", "Series 3a (2M)", MACHINE_NOT_WORKING ) +COMP( 1995, psion3a2_de, psion3a, 0, psion3a2, psion3a_de, psion3a_state, empty_init, "Psion", "Series 3a (2M) (German)", MACHINE_NOT_WORKING ) +COMP( 1996, psion3c, 0, 0, psion3c, psion3c, psion3a_state, empty_init, "Psion", "Series 3c", MACHINE_NOT_WORKING ) +COMP( 1998, psion3mx, 0, 0, psion3mx, psion3c, psion3a_state, empty_init, "Psion", "Series 3mx", MACHINE_NOT_WORKING ) diff --git a/src/mame/psion/psion_ssd.cpp b/src/mame/psion/psion_ssd.cpp new file mode 100644 index 00000000000..ab59d210f5b --- /dev/null +++ b/src/mame/psion/psion_ssd.cpp @@ -0,0 +1,284 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/**************************************************************************** + + Psion Solid State Disk emulation + + + Memory Type No. devices Memory Size + D7 D6 D5 D4 D3 D2 D1 D0 + 0 0 0 RAM 0 0 1 device 0 0 0 No memory + 0 0 1 Type 1 Flash 0 1 2 devices 0 0 1 32K + 0 1 0 Type 2 Flash 1 0 3 devices 0 1 0 64K + 0 1 1 Type 3 Flash 1 1 4 devices 0 1 1 128K + 1 0 0 Type 4 Flash 1 0 0 256K + 1 0 1 Type 5 Flash 1 0 1 512K + 1 1 0 Read only SSD (ROM) 1 1 0 1M + 1 1 1 Hardware Write protected SSD 1 1 1 2M + + Info Byte (* = confirmed) + Psion Solid State Disk 64K Flash 001 01 001 0x29 + Psion Solid State Disk 128K Flash * 001 00 011 0x23 + - MC200 System Disk * 111 00 011 0xE3 + - MC400 System Disk * 111 00 011 0xE3 + Psion Solid State Disk 256K Flash * 001 01 011 0x2B + - MC Word System Disk * 111 01 011 0xEB + Psion Solid State Disk 512K Flash 001 01 100 0x2C + Psion Solid State Disk 1MB Flash * 001 11 100 0x3C + Psion Solid State Disk 2MB Flash * 001 11 101 0x3D + Psion Solid State Disk 4MB Flash 001 11 110 0x3E + Psion Solid State Disk 8MB Flash * 001 11 111 0x3F + + Psion Solid State Disk 64K RAM 000 01 001 0x09 + Psion Solid State Disk 128K RAM 000 11 001 0x19 + Psion Solid State Disk 512K RAM 000 11 011 0x1B + Psion Solid State Disk 1MB RAM 000 11 100 0x1C + Psion Solid State Disk 2MB RAM 000 11 101 0x1D + +****************************************************************************/ + +#include "emu.h" +#include "psion_ssd.h" + +#include "softlist_dev.h" + + +DEFINE_DEVICE_TYPE(PSION_SSD, psion_ssd_device, "psion_ssd", "Psion Solid State Disk") + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void psion_ssd_device::device_add_mconfig(machine_config &config) +{ + PSION_ASIC5_PACK(config, m_asic5); + m_asic5->readpa_handler().set([this]() { return m_ssd_data[latched_addr()]; }); + m_asic5->writepa_handler().set([this](uint8_t data) { m_ssd_data[latched_addr()] = data; }); + m_asic5->writepb_handler().set([this](uint8_t data) { m_addr_latch = (m_addr_latch & 0xffff00) | (data << 0); }); + m_asic5->writepd_handler().set([this](uint8_t data) { m_addr_latch = (m_addr_latch & 0xff00ff) | (data << 8); }); + m_asic5->writepc_handler().set([this](uint8_t data) { m_addr_latch = (m_addr_latch & 0x00ffff) | (data << 16); }); +} + + +//------------------------------------------------- +// psion_ssd_device - constructor +//------------------------------------------------- + +psion_ssd_device::psion_ssd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, PSION_SSD, tag, owner, clock) + , device_memcard_image_interface(mconfig, *this) + , m_region(*this, DEVICE_SELF) + , m_asic5(*this, "asic5") + , m_door_cb(*this) + , m_door_timer(nullptr) + , m_info_byte(0) + , m_addr_latch(0) + , m_mem_width(0) +{ +} + + +//------------------------------------------------- +// psion_ssd_device - destructor +//------------------------------------------------- + +psion_ssd_device::~psion_ssd_device() +{ +} + + +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void psion_ssd_device::device_resolve_objects() +{ + m_door_cb.resolve_safe(); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void psion_ssd_device::device_start() +{ + m_ssd_data = make_unique_clear(0x800000); + + // insert default System disk + if (m_region.found()) + { + uint32_t size = m_region->bytes(); + memcpy(&m_ssd_data[0], m_region->base(), size); + set_info_byte(size, SSD_FLASH1); + } + + m_door_timer = timer_alloc(FUNC(psion_ssd_device::close_door), this); + m_door_timer->reset(); + + save_pointer(NAME(m_ssd_data), 0x800000); + save_item(NAME(m_info_byte)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void psion_ssd_device::device_reset() +{ + m_addr_latch = 0x00; + + // open the door + m_door_cb(ASSERT_LINE); + + // setup the timer to close the door + m_door_timer->adjust(attotime::from_msec(200)); +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void psion_ssd_device::device_config_complete() +{ + add_format("ssd", "Psion Solid State Disk image", "bin,rom", ""); +} + + +//------------------------------------------------- +// get_software_list_loader - +//------------------------------------------------- + +const software_list_loader &psion_ssd_device::get_software_list_loader() const +{ + return image_software_list_loader::instance(); +} + + + +TIMER_CALLBACK_MEMBER(psion_ssd_device::close_door) +{ + // close the door + m_door_cb(CLEAR_LINE); +} + + +image_init_result psion_ssd_device::call_load() +{ + device_image_interface *image = nullptr; + interface(image); + + uint32_t size = image->length(); + + if (size < 0x10000 || size > 0x800000 || (size & (size - 1)) != 0) + { + image->seterror(image_error::INVALIDIMAGE, "Invalid size, must be 64K, 128K, 256K, 512K, 1M, 2M, 4M, 8M"); + return image_init_result::FAIL; + } + + image->fread(m_ssd_data.get(), size); + + // check for Flash header + if ((m_ssd_data[0] | (m_ssd_data[1] << 8)) == 0xf1a5) // Flash + set_info_byte(size, SSD_FLASH1); + else + set_info_byte(size, SSD_RAM); + + // open the door + m_door_cb(ASSERT_LINE); + + // setup the timer to close the door + m_door_timer->adjust(attotime::from_msec(200)); + + return image_init_result::PASS; +} + + +void psion_ssd_device::call_unload() +{ + memset(m_ssd_data.get(), 0, sizeof(m_ssd_data)); + set_info_byte(0); +} + + +uint32_t psion_ssd_device::latched_addr() +{ + return (m_addr_latch & make_bitmask(m_mem_width)) | (BIT(m_addr_latch, 22, 2) << m_mem_width); +} + + +void psion_ssd_device::set_info_byte(uint32_t size, uint8_t type) +{ + m_info_byte = 0x00; + + // Type 1 Flash or RAM + if (type != SSD_RAM) + m_info_byte |= 0x20; + + // No. devices and size + switch (size) + { + case 0x010000: // 64K (2 x 32K) + m_info_byte = 0x09; + m_mem_width = 15; + break; + case 0x020000: // 128K (1 x 128K) + m_info_byte = 0x03; + m_mem_width = 17; + break; + case 0x040000: // 256K (2 x 128K) + m_info_byte = 0x0b; + m_mem_width = 17; + break; + case 0x080000: // 512K (2 x 256K) + m_info_byte = 0x0c; + m_mem_width = 18; + break; + case 0x100000: // 1M (4 x 256K) + m_info_byte = 0x1c; + m_mem_width = 18; + break; + case 0x200000: // 2M (4 x 512K) + m_info_byte = 0x1d; + m_mem_width = 19; + break; + case 0x400000:// 4M (4 x 1M) + m_info_byte = 0x1e; + m_mem_width = 20; + break; + case 0x800000:// 8M (4 x 2M) + m_info_byte = 0x1f; + m_mem_width = 21; + break; + } + + // write protected + m_info_byte |= 0xe0; + + // set pull-ups on ASIC5 + m_asic5->set_info_byte(m_info_byte); +} + + +uint8_t psion_ssd_device::data_r() +{ + if (m_info_byte) + { + return m_asic5->data_r(); + } + return 0x00; +} + +void psion_ssd_device::data_w(uint16_t data) +{ + if (m_info_byte) + { + m_asic5->data_w(data); + } +} diff --git a/src/mame/psion/psion_ssd.h b/src/mame/psion/psion_ssd.h new file mode 100644 index 00000000000..c7df0b8f033 --- /dev/null +++ b/src/mame/psion/psion_ssd.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/**************************************************************************** + + Psion Solid State Disk emulation + +****************************************************************************/ + +#ifndef MAME_PSION_PSION_SSD_H +#define MAME_PSION_PSION_SSD_H + +#include "machine/psion_asic5.h" +#include "imagedev/memcard.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +// ======================> psion_ssd_device + +class psion_ssd_device : public device_t, public device_memcard_image_interface +{ +public: + // construction/destruction + psion_ssd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + virtual ~psion_ssd_device(); + + // callbacks + auto door_cb() { return m_door_cb.bind(); } + + uint8_t data_r(); + void data_w(uint16_t data); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_config_complete() override; + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + // image-level overrides + virtual image_init_result call_load() override; + virtual void call_unload() override; + + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual const char *image_interface() const noexcept override { return "psion_ssd"; } + virtual const char *file_extensions() const noexcept override { return "rom,bin"; } + virtual const char *image_type_name() const noexcept override { return "ssd"; } + virtual const char *image_brief_type_name() const noexcept override { return "ssd"; } + + // device_image_interface implementation + virtual const software_list_loader &get_software_list_loader() const override; + +private: + optional_memory_region m_region; + required_device m_asic5; + + inline uint32_t mem_addr() const noexcept { return (m_addr_latch & make_bitmask(m_mem_width)) | (BIT(m_addr_latch, 22, 2) << m_mem_width); } + + TIMER_CALLBACK_MEMBER(close_door); + + devcb_write_line m_door_cb; + emu_timer *m_door_timer; + + std::unique_ptr m_ssd_data; + + void set_info_byte(uint32_t size, uint8_t type = 0); + uint32_t latched_addr(); + + uint8_t m_info_byte; + uint32_t m_addr_latch; + int m_mem_width; + + static constexpr uint8_t SSD_RAM = 0; + static constexpr uint8_t SSD_FLASH1 = 1; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(PSION_SSD, psion_ssd_device) + +#endif // MAME_PSION_PSION_SSD_H diff --git a/src/mame/psion/siena.cpp b/src/mame/psion/siena.cpp new file mode 100644 index 00000000000..c8631fd43cb --- /dev/null +++ b/src/mame/psion/siena.cpp @@ -0,0 +1,226 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/****************************************************************************** + + Psion Siena + + TODO: + - battery backed RAM + +******************************************************************************/ + +#include "emu.h" +#include "machine/psion_asic9.h" +#include "machine/ram.h" +#include "sound/spkrdev.h" + +#include "emupal.h" +#include "screen.h" +#include "softlist_dev.h" +#include "speaker.h" +#include "utf8.h" + + +namespace { + +class siena_state : public driver_device +{ +public: + siena_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_asic9(*this, "asic9") + , m_ram(*this, "ram") + , m_palette(*this, "palette") + , m_keyboard(*this, "COL%u", 0U) + , m_speaker(*this, "speaker") + { } + + void siena(machine_config &config); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + +private: + required_device m_asic9; + required_device m_ram; + required_device m_palette; + required_ioport_array<8> m_keyboard; + required_device m_speaker; + + void palette_init(palette_device &palette); + + uint16_t kbd_r(); + + uint8_t m_key_col = 0; +}; + + +void siena_state::machine_start() +{ +} + +void siena_state::machine_reset() +{ +} + + +static INPUT_PORTS_START( siena ) + PORT_START("COL0") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR('7') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR('6') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR('5') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR('4') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR('3') PORT_NAME("3 MC") + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR('2') PORT_NAME("2 MR") + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR('1') PORT_NAME("1 Min") + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR('0') + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("On/CE") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_UNKNOWN) + + PORT_START("COL1") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR('"') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR('/') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR('(') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR('8') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("Fn") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGUP) PORT_NAME("IR Send") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("Word") + + PORT_START("COL2") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0xa3) + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR('~') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_NAME("Help") + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(')') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR('9') + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) PORT_NAME("Psion") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGDN) PORT_NAME("IR Receive") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("Agenda") + + PORT_START("COL3") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR('$') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR('@') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME(UTF8_LEFT" Home") + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_NAME("= %") + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (L)") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Off") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("Time") + + PORT_START("COL4") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR('%') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') PORT_CHAR('{') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME(UTF8_DOWN" Pg Dn") + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME(UTF8_UP" Pg Up") + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("Enter") + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR('+') PORT_NAME("+ M+") + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (R)") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("World") + + PORT_START("COL5") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR('^') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') PORT_CHAR('}') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME(UTF8_RIGHT" End") + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x08) PORT_NAME("Del") + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR('*') PORT_NAME(u8"×") + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_UNKNOWN) + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("Sheet") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("Calc") + + PORT_START("COL6") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR('!') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR('\\') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_NAME("Caps") + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(']') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR('*') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR('/') PORT_NAME(u8"÷") + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR('-') PORT_NAME("- M-") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_NAME("Esc") + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("Data") + + PORT_START("COL7") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(0x09) PORT_NAME("Tab") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR('#') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) PORT_NAME("Menu Info") + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR('[') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR('&') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR('.') PORT_NAME(". +/-") + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Control") + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("System") +INPUT_PORTS_END + + +uint16_t siena_state::kbd_r() +{ + uint16_t data = 0x00; + + for (int i = 0; i < 8; i++) + { + if (BIT(m_key_col, i)) + data |= m_keyboard[i]->read(); + } + + return data; +} + + +void siena_state::palette_init(palette_device &palette) +{ + palette.set_pen_color(0, rgb_t(190, 220, 190)); + palette.set_pen_color(1, rgb_t(130, 130, 110)); + palette.set_pen_color(2, rgb_t(190, 210, 180)); +} + + +void siena_state::siena(machine_config &config) +{ + PSION_ASIC9(config, m_asic9, 7.68_MHz_XTAL); + m_asic9->set_ram_rom("ram", "rom"); + m_asic9->port_ab_r().set(FUNC(siena_state::kbd_r)); + m_asic9->buz_cb().set(m_speaker, FUNC(speaker_sound_device::level_w)); + m_asic9->col_cb().set([this](uint8_t data) { m_key_col = data; }); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); + screen.set_size(240, 160); + screen.set_visarea_full(); + screen.set_refresh_hz(66); + screen.set_screen_update(m_asic9, FUNC(psion_asic9_device::screen_update)); + screen.set_palette(m_palette); + PALETTE(config, "palette", FUNC(siena_state::palette_init), 3); + + SPEAKER(config, "mono").front_center(); + SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00); // Piezo buzzer + + RAM(config, m_ram).set_default_size("512K").set_extra_options("1M"); + + // TODO: add Honda port + + SOFTWARE_LIST(config, "ssd_list").set_original("psion_ssd").set_filter("WA"); +} + + +ROM_START(siena) + ROM_REGION16_LE(0x100000, "rom", 0) + ROM_SYSTEM_BIOS(0, "420f", "V4.20F") + ROMX_LOAD("vine_v4.20f.bin", 0x00000, 0x100000, CRC(641f8e7c) SHA1(fe0e46540e0aac5aabb2dd1b96689da41e8f55fb), ROM_BIOS(0)) +ROM_END + +} // anonymous namespace + + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1996, siena, 0, 0, siena, siena, siena_state, empty_init, "Psion", "Siena", MACHINE_NOT_WORKING ) diff --git a/src/mame/psion/workabout.cpp b/src/mame/psion/workabout.cpp new file mode 100644 index 00000000000..685697e7d36 --- /dev/null +++ b/src/mame/psion/workabout.cpp @@ -0,0 +1,265 @@ +// license:BSD-3-Clause +// copyright-holders:Nigel Barnes +/****************************************************************************** + + Psion Workabout + + TODO: + - battery backed RAM + +******************************************************************************/ + +#include "emu.h" +#include "machine/psion_asic9.h" +#include "machine/ram.h" +#include "sound/spkrdev.h" +//#include "bus/psion/exp/slot.h" +#include "psion_ssd.h" + +#include "emupal.h" +#include "screen.h" +#include "softlist_dev.h" +#include "speaker.h" +#include "utf8.h" + + +namespace { + +class workabout_state : public driver_device +{ +public: + workabout_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_asic9(*this, "asic9") + , m_ram(*this, "ram") + , m_palette(*this, "palette") + , m_keyboard(*this, "COL%u", 0U) + , m_speaker(*this, "speaker") + , m_ssd(*this, "ssd%u", 1U) + //, m_exp(*this, "exp%u", 1U) + { } + + void workabout(machine_config &config); + void psionwa(machine_config &config); + void psionwamx(machine_config &config); + +protected: + virtual void machine_start() override; + virtual void machine_reset() override; + +private: + required_device m_asic9; + required_device m_ram; + required_device m_palette; + required_ioport_array<8> m_keyboard; + required_device m_speaker; + required_device_array m_ssd; + //required_device_array m_exp; + + void palette_init(palette_device &palette); + + uint16_t kbd_r(); + + uint8_t m_key_col = 0; +}; + + +void workabout_state::machine_start() +{ +} + +void workabout_state::machine_reset() +{ +} + + +static INPUT_PORTS_START( workabout ) + PORT_START("COL0") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') PORT_CHAR('}') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME(UTF8_DOWN) + PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_NAME("On/Esc") + + PORT_START("COL1") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("Enter") + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME(UTF8_RIGHT) + PORT_BIT(0x180, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("COL2") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_NAME("1 ! @") + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_CHAR('\'') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x08) PORT_NAME("Del") + PORT_BIT(0x180, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("COL3") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("Psion") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_CHAR('#') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') PORT_CHAR('[') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(0x09) PORT_NAME("Tab") + PORT_BIT(0x180, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("COL4") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(0xa3) PORT_CHAR('\\') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') PORT_CHAR(']') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME(UTF8_UP) + PORT_BIT(0x180, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("COL5") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('=') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('*') PORT_CHAR(':') + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) PORT_NAME("Menu") + PORT_BIT(0x180, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("COL6") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Control") + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(';') PORT_CHAR('<') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('~') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Contrast") + PORT_BIT(0x180, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("COL7") + PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(',') + PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CHAR('{') + PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME(UTF8_LEFT) + PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backlight") + PORT_BIT(0x180, IP_ACTIVE_HIGH, IPT_UNUSED) +INPUT_PORTS_END + + +uint16_t workabout_state::kbd_r() +{ + uint16_t data = 0x00; + + for (int i = 0; i < 8; i++) + { + if (BIT(m_key_col, i)) + data |= m_keyboard[i]->read(); + } + + return data; +} + + +void workabout_state::palette_init(palette_device &palette) +{ + palette.set_pen_color(0, rgb_t(190, 220, 190)); + palette.set_pen_color(1, rgb_t(130, 130, 110)); + palette.set_pen_color(2, rgb_t(190, 210, 180)); +} + + +void workabout_state::workabout(machine_config &config) +{ + PSION_ASIC9(config, m_asic9, 7.68_MHz_XTAL); // V30H + m_asic9->set_ram_rom("ram", "rom"); + m_asic9->port_ab_r().set(FUNC(workabout_state::kbd_r)); + m_asic9->buz_cb().set(m_speaker, FUNC(speaker_sound_device::level_w)); + m_asic9->col_cb().set([this](uint8_t data) { m_key_col = data; }); + m_asic9->data_r<0>().set(m_ssd[0], FUNC(psion_ssd_device::data_r)); // SSD Pack 1 + m_asic9->data_w<0>().set(m_ssd[0], FUNC(psion_ssd_device::data_w)); + m_asic9->data_r<1>().set(m_ssd[1], FUNC(psion_ssd_device::data_r)); // SSD Pack 2 + m_asic9->data_w<1>().set(m_ssd[1], FUNC(psion_ssd_device::data_w)); + //m_asic9->data_r<2>().set(m_exp[0], FUNC(psion_exp_slot_device::data_r)); // Expansion port A + //m_asic9->data_w<2>().set(m_exp[0], FUNC(psion_exp_slot_device::data_w)); + //m_asic9->data_r<3>().set(m_exp[1], FUNC(psion_exp_slot_device::data_r)); // Expansion port B + //m_asic9->data_w<3>().set(m_exp[1], FUNC(psion_exp_slot_device::data_w)); + //m_asic9->data_r<4>().set(m_exp[2], FUNC(psion_exp_slot_device::data_r)); // Expansion port C + //m_asic9->data_w<4>().set(m_exp[2], FUNC(psion_exp_slot_device::data_w)); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); + screen.set_size(240, 100); + screen.set_visarea_full(); + screen.set_refresh_hz(66); + screen.set_screen_update(m_asic9, FUNC(psion_asic9_device::screen_update)); + screen.set_palette(m_palette); + PALETTE(config, "palette", FUNC(workabout_state::palette_init), 3); + + SPEAKER(config, "mono").front_center(); + SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00); // Piezo buzzer + + RAM(config, m_ram); + + PSION_SSD(config, m_ssd[0]); + m_ssd[0]->door_cb().set(m_asic9, FUNC(psion_asic9_device::medchng_w)); + PSION_SSD(config, m_ssd[1]); + m_ssd[1]->door_cb().set(m_asic9, FUNC(psion_asic9_device::medchng_w)); + + //PSION_EXP_SLOT(config, m_exp[0], psion_exp_devices, nullptr); + //PSION_EXP_SLOT(config, m_exp[1], psion_exp_devices, nullptr); + //PSION_EXP_SLOT(config, m_exp[2], psion_exp_devices, nullptr); + + SOFTWARE_LIST(config, "ssd_list").set_original("psion_ssd").set_filter("WA"); +} + + +void workabout_state::psionwa(machine_config &config) +{ + workabout(config); + + m_ram->set_default_size("1M"); +} + +void workabout_state::psionwamx(machine_config &config) +{ + workabout(config); + + m_asic9->set_clock(3.6864_MHz_XTAL * 15 / 2); // V30MX + + m_ram->set_default_size("2M"); +} + + +ROM_START(psionwa) + ROM_REGION16_LE(0x200000, "rom", 0) + ROM_SYSTEM_BIOS(0, "240f", "V2.40F 060897") + ROMX_LOAD("w1_v2.40f.bin", 0x00000, 0x200000, CRC(4ef1d380) SHA1(d155edf7995c2a799525b53079fff9fb68789f0f), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "100f", "V1.00F 010195") + ROMX_LOAD("w1_v1.00f.bin", 0x00000, 0x100000, CRC(8fd7c127) SHA1(316fdc6c54629470f1af3295c46a2e7d58ebdca9), ROM_BIOS(1)) + ROM_RELOAD(0x100000, 0x100000) + ROM_SYSTEM_BIOS(2, "024b", "V0.24B 120296") + ROMX_LOAD("w1_v0.24b.bin", 0x00000, 0x200000, CRC(6e7e3016) SHA1(5c35eea431f975cdefc770697a88fe62a1e7af7f), ROM_BIOS(2)) +ROM_END + +ROM_START(psionwamx) + ROM_REGION16_LE(0x200000, "rom", 0) + ROM_SYSTEM_BIOS(0, "720f", "V7.20F 230798") + ROMX_LOAD("w2mx_v7.20f.bin", 0x00000, 0x200000, CRC(63734683) SHA1(9d8aa1e45f52e7fcb52d6e81ac47f60d1104c35d), ROM_BIOS(0)) +ROM_END + +} // anonymous namespace + + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1995, psionwa, 0, 0, psionwa, workabout, workabout_state, empty_init, "Psion", "Workabout", MACHINE_NOT_WORKING ) +COMP( 1998, psionwamx, 0, 0, psionwamx, workabout, workabout_state, empty_init, "Psion", "Workabout mx", MACHINE_NOT_WORKING ) -- cgit v1.2.3