diff options
| author | 2026-05-16 15:40:39 +0100 | |
|---|---|---|
| committer | 2026-05-16 16:15:25 +0100 | |
| commit | a7e361f36bf7987c664d1122b58fe8bd95b8fc43 (patch) | |
| tree | e31a9b624bbeaf093663c64d22a94d2185108f1b /src | |
| parent | db06859d70db1ae60c3b70432b7e891407d8314d (diff) | |
New systems marked not working
------------------------------
Series 5mx PRO [Nigel Barnes, Bs()Dd]
Revo [Nigel Barnes]
MC 218 [Nigel Barnes]
New clones marked not working
-----------------------------
Series 5mx (French) [Nigel Barnes]
Series 5mx PRO (German) [Nigel Barnes, Bs()Dd]
Revo (German) [Nigel Barnes]
Revo (French) [Nigel Barnes]
Diamond Mako [Nigel Barnes]
MC 218 (German) [Nigel Barnes]
MC 218 (French) [Nigel Barnes]
psion/psion5mx.cpp: Devicified the Windermere SoC.
- Demoted Series 5mx to not working (until Time app issue is fixed).
- Expanded screen to match digitiser area, can now select apps from bezel overlay region.
- Added CODEC audio device, and volume control.
- RAM contents are now non-volatile.
- Now uses an EEPROM device, and improved default contents.
psion/etna.cpp: Removed PROM handling, and added port handlers.
Diffstat (limited to 'src')
| -rw-r--r-- | src/mame/mame.lst | 10 | ||||
| -rw-r--r-- | src/mame/psion/etna.cpp | 132 | ||||
| -rw-r--r-- | src/mame/psion/etna.h | 44 | ||||
| -rw-r--r-- | src/mame/psion/psion5mx.cpp | 1451 | ||||
| -rw-r--r-- | src/mame/psion/psion5mx.h | 216 | ||||
| -rw-r--r-- | src/mame/psion/windermere.cpp | 990 | ||||
| -rw-r--r-- | src/mame/psion/windermere.h | 263 |
7 files changed, 1933 insertions, 1173 deletions
diff --git a/src/mame/mame.lst b/src/mame/mame.lst index af3c9284c07..c2060c06acd 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -40374,7 +40374,17 @@ psion3mx_fr psion3mx_nl @source:psion/psion5mx.cpp +mako +mc218 +mc218_de +mc218_fr psion5mx +psion5mx_fr +psion5mxp +psion5mxp_de +revo +revo_de +revo_fr @source:psion/psionhc.cpp psionhc100 diff --git a/src/mame/psion/etna.cpp b/src/mame/psion/etna.cpp index bd7ef27307d..a8bce4b6335 100644 --- a/src/mame/psion/etna.cpp +++ b/src/mame/psion/etna.cpp @@ -2,88 +2,47 @@ // copyright-holders:Ryan Holtz, Ash Wolf /*************************************************************************** - Psion 5mx (EPOC R5) series ETNA peripheral + Psion ASIC12 (ETNA) peripheral - Skeleton device by Ryan Holtz, ported from work by Ash Wolf + ETNA is a peripheral ASIC incorporating a PCMCIA controller. - More info: - https://github.com/Treeki/WindEmu + More info: + https://github.com/Treeki/WindEmu ****************************************************************************/ +#include "emu.h" #include "etna.h" + #define LOG_READS (1U << 1) #define LOG_WRITES (1U << 2) -#define LOG_UNKNOWNS (1U << 3) -#define LOG_PROM (1U << 4) -#define LOG_ALL (LOG_READS | LOG_WRITES | LOG_UNKNOWNS | LOG_PROM) +#define LOG_UNKNOWN (1U << 3) +#define LOG_ALL (LOG_READS | LOG_WRITES | LOG_UNKNOWN) #define VERBOSE (0) #include "logmacro.h" -DEFINE_DEVICE_TYPE(ETNA, etna_device, "etna", "Psion 5mx ETNA") +DEFINE_DEVICE_TYPE(ETNA, etna_device, "etna", "Psion ASIC12 (ETNA)") etna_device::etna_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, ETNA, tag, owner, clock) - , m_eeprom_data_out(*this) + , m_porta_r(*this, 0x00) + , m_porta_w(*this) { } void etna_device::device_start() { - save_item(NAME(m_prom_addr_count)); - save_item(NAME(m_prom_addr)); - save_item(NAME(m_prom_value)); - save_item(NAME(m_prom_cs)); - save_item(NAME(m_prom_clk)); - save_item(NAME(m_pending_ints)); - save_item(NAME(m_regs)); - save_item(NAME(m_prom)); } void etna_device::device_reset() { - m_prom_addr_count = 0; - m_prom_addr = 0; - m_prom_value = 0; - m_prom_cs = false; - m_prom_clk = false; - m_pending_ints = 0; std::fill(std::begin(m_regs), std::end(m_regs), 0); - std::fill(std::begin(m_prom), std::end(m_prom), 0); - - // defaults expected by the touchscreen code - m_prom[0x0a] = 20; - m_prom[0x0b] = 20; - m_prom[0x0c] = 20; - m_prom[0x0d] = 30; - - // some basic stuff to begin with - // set up the Psion's unique ID - m_prom[0x1b] = 0xde; - m_prom[0x1a] = 0xad; - m_prom[0x19] = 0xbe; - m_prom[0x18] = 0xef; - - // give ourselves a neat custom device name - const char *key = "PSION"; - const char *name = "MAME!"; - m_prom[0x28] = strlen(name); - for (int i = 0; i < m_prom[0x28]; i++) - m_prom[0x29 + i] = name[i] ^ key[i]; - - // calculate the checksum - uint8_t chk = 0; - for (int i = 0; i < 0x7F; i++) - chk ^= m_prom[i]; - - // EPOC is expecting 66 - m_prom[0x7f] = chk ^ 66; } void etna_device::regs_w(offs_t offset, uint8_t data) @@ -127,9 +86,10 @@ void etna_device::regs_w(offs_t offset, uint8_t data) case REG_SKT_CTRL: LOGMASKED(LOG_WRITES, "%s: etna reg write: SKT_CTRL = %02x\n", machine().describe_context(), data); break; - case REG_WAKE1: - LOGMASKED(LOG_WRITES, "%s: etna reg write: WAKE1 = %02x\n", machine().describe_context(), data); - m_regs[REG_WAKE1] = data; + case REG_PORTA: + LOGMASKED(LOG_WRITES, "%s: etna reg write: PORTA = %02x\n", machine().describe_context(), data); + //m_regs[REG_PORTA] = data; + m_porta_w(data); break; case REG_SKT_VAR_B0: LOGMASKED(LOG_WRITES, "%s: etna reg write: SKT_VAR_B0 = %02x\n", machine().describe_context(), data); @@ -142,7 +102,7 @@ void etna_device::regs_w(offs_t offset, uint8_t data) m_regs[REG_WAKE2] = data; break; default: - LOGMASKED(LOG_UNKNOWNS, "%s: etna reg write: Unknown = %02x\n", machine().describe_context(), data); + LOGMASKED(LOG_UNKNOWN, "%s: etna reg write: Unknown = %02x\n", machine().describe_context(), data); break; } } @@ -150,6 +110,7 @@ void etna_device::regs_w(offs_t offset, uint8_t data) uint8_t etna_device::regs_r(offs_t offset) { uint8_t data = 0; + switch (offset) { case REG_UNK0: @@ -177,21 +138,24 @@ uint8_t etna_device::regs_r(offs_t offset) LOGMASKED(LOG_READS, "%s: etna reg read: PCCD_INT_MASK = %02x\n", machine().describe_context(), data); break; case REG_INT_CLEAR: + data = 0; LOGMASKED(LOG_READS, "%s: etna reg read: INT_CLEAR = %02x\n", machine().describe_context(), data); break; case REG_SKT_VAR_A0: - LOGMASKED(LOG_READS, "%s: etna reg read: SKT_VAR_A0 = %02x\n", machine().describe_context(), data); data = 1; + LOGMASKED(LOG_READS, "%s: etna reg read: SKT_VAR_A0 = %02x\n", machine().describe_context(), data); break; case REG_SKT_VAR_A1: + data = 0; LOGMASKED(LOG_READS, "%s: etna reg read: SKT_VAR_A1 = %02x\n", machine().describe_context(), data); break; case REG_SKT_CTRL: LOGMASKED(LOG_READS, "%s: etna reg read: SKT_CTRL = %02x\n", machine().describe_context(), data); break; - case REG_WAKE1: - data = m_regs[REG_WAKE1]; - LOGMASKED(LOG_READS, "%s: etna reg read: WAKE1 = %02x\n", machine().describe_context(), data); + case REG_PORTA: + //data = m_regs[REG_PORTA]; + data = m_porta_r(); + LOGMASKED(LOG_READS, "%s: etna reg read: PORTA = %02x\n", machine().describe_context(), data); break; case REG_SKT_VAR_B0: LOGMASKED(LOG_READS, "%s: etna reg read: SKT_VAR_B0 = %02x\n", machine().describe_context(), data); @@ -204,54 +168,8 @@ uint8_t etna_device::regs_r(offs_t offset) LOGMASKED(LOG_READS, "%s: etna reg read: WAKE2 = %02x\n", machine().describe_context(), data); break; default: - LOGMASKED(LOG_UNKNOWNS, "%s: etna reg read: Unknown = %02x\n", machine().describe_context(), data); + LOGMASKED(LOG_UNKNOWN, "%s: etna reg read: Unknown = %02x\n", machine().describe_context(), data); break; } return data; } - -void etna_device::eeprom_cs_in(int state) -{ - bool old = m_prom_cs; - m_prom_cs = state; - if (!old && m_prom_cs) - { - m_prom_addr_count = 0; - m_prom_addr = 0; - m_prom_value = 0; - } -} - -void etna_device::eeprom_clk_in(int state) -{ - bool old = m_prom_clk; - m_prom_clk = state; - - if (!old && m_prom_clk) - { - if (m_prom_addr_count < 10) - { - m_prom_addr <<= 1; - m_prom_addr |= BIT(m_regs[REG_WAKE1], 2); - m_prom_addr_count++; - if (m_prom_addr_count == 10) - { - LOGMASKED(LOG_PROM, "PROM Address: %03x\n", m_prom_addr); - uint16_t byte_addr = (m_prom_addr << 1) % std::size(m_prom); - m_prom_value = m_prom[byte_addr] | (m_prom[byte_addr + 1] << 8); - LOGMASKED(LOG_PROM, "PROM Value: %04x\n", m_prom_value); - } - } - else - { - m_regs[REG_WAKE1] &= ~0x08; - m_regs[REG_WAKE1] |= BIT(m_prom_value, 15) << 3; - LOGMASKED(LOG_PROM, "PROM Bit: %d\n", BIT(m_prom_value, 15)); - m_prom_value <<= 1; - } - } -} - -void etna_device::eeprom_data_in(int state) -{ -} diff --git a/src/mame/psion/etna.h b/src/mame/psion/etna.h index 0c153e4835d..64410ba2264 100644 --- a/src/mame/psion/etna.h +++ b/src/mame/psion/etna.h @@ -2,9 +2,7 @@ // copyright-holders:Ryan Holtz, Ash Wolf /*************************************************************************** - Psion 5mx (EPOC R5) series ETNA peripheral - - Skeleton driver by Ryan Holtz, ported from work by Ash Wolf + Psion ASIC12 (ETNA) peripheral ****************************************************************************/ @@ -13,27 +11,37 @@ #pragma once -#include "emu.h" class etna_device : public device_t { public: etna_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + auto porta_r() { return m_porta_r.bind(); } + auto porta_w() { return m_porta_w.bind(); } + void regs_w(offs_t offset, uint8_t data); uint8_t regs_r(offs_t offset); - void eeprom_cs_in(int state); - void eeprom_clk_in(int state); - void eeprom_data_in(int state); - - auto eeprom_data_out() { return m_eeprom_data_out.bind(); } - -private: - // device-level overrides + //void write_pc1_bvd1(int state) { set_input_level(PC1_BVD1, state); } + //void write_pc1_bvd2(int state) { set_input_level(PC1_BVD2, state); } + //void write_pc1_cd1(int state) { set_input_level(PC1_CD1, state); } + //void write_pc1_cd2(int state) { set_input_level(PC1_CD2, state); } + //void write_pc1_wp(int state) { set_input_level(PC1_WP, state); } + //void write_pc2_bvd1(int state) { set_input_level(PC2_BVD1, state); } + //void write_pc2_bvd2(int state) { set_input_level(PC2_BVD2, state); } + //void write_pc2_cd1(int state) { set_input_level(PC2_CD1, state); } + //void write_pc2_cd2(int state) { set_input_level(PC2_CD2, state); } + //void write_pc2_wp(int state) { set_input_level(PC2_WP, state); } + +protected: + // device_t overrides virtual void device_start() override ATTR_COLD; virtual void device_reset() override ATTR_COLD; +private: + //void set_input_level(uint16_t mask, int state); + enum { REG_UNK0, @@ -48,24 +56,18 @@ private: REG_SKT_VAR_A0, REG_SKT_VAR_A1, REG_SKT_CTRL, - REG_WAKE1, + REG_PORTA, REG_SKT_VAR_B0, REG_SKT_VAR_B1, REG_WAKE2 }; - devcb_write_line m_eeprom_data_out; - - uint8_t m_prom_addr_count; - uint16_t m_prom_addr; - uint16_t m_prom_value; - bool m_prom_cs; - bool m_prom_clk; + devcb_read8 m_porta_r; + devcb_write8 m_porta_w; uint8_t m_pending_ints; uint8_t m_regs[0x10]; - uint8_t m_prom[0x80]; }; DECLARE_DEVICE_TYPE(ETNA, etna_device) diff --git a/src/mame/psion/psion5mx.cpp b/src/mame/psion/psion5mx.cpp index f596673fc62..7a528414840 100644 --- a/src/mame/psion/psion5mx.cpp +++ b/src/mame/psion/psion5mx.cpp @@ -1,975 +1,768 @@ // license:BSD-3-Clause -// copyright-holders:Ryan Holtz, Ash Wolf +// copyright-holders:Ryan Holtz, Nigel Barnes /*************************************************************************** - Psion 5mx (EPOC R5) series + Psion Series 5mx (EPOC R5) Driver by Ryan Holtz, ported from work by Ash Wolf - TODO: - - Audio - - UART support - - Probably more + More info: https://github.com/Treeki/WindEmu - More info: - https://github.com/Treeki/WindEmu + TODO: + - Audio (MSM7717) + - UART support (Windermere) + - Compact Flash (Etna) + - Bezel artwork ****************************************************************************/ -#include "psion5mx.h" - -#include "utf8.h" - -#define LOG_UNKNOWNS (1U << 1) -#define LOG_IRQ (1U << 2) -#define LOG_DISPLAY (1U << 3) -#define LOG_DRAM_READS (1U << 4) -#define LOG_LCD_READS (1U << 5) -#define LOG_POWER_READS (1U << 6) -#define LOG_EOI_READS (1U << 7) -#define LOG_INT_READS (1U << 8) -#define LOG_CODEC_READS (1U << 9) -#define LOG_SSP_READS (1U << 10) -#define LOG_TIMER_READS (1U << 11) -#define LOG_BUZZER_READS (1U << 12) -#define LOG_RTC_READS (1U << 13) -#define LOG_GPIO_READS (1U << 14) -#define LOG_KBD_READS (1U << 15) -#define LOG_DRAM_WRITES (1U << 16) -#define LOG_LCD_WRITES (1U << 17) -#define LOG_POWER_WRITES (1U << 18) -#define LOG_EOI_WRITES (1U << 19) -#define LOG_INT_WRITES (1U << 20) -#define LOG_CODEC_WRITES (1U << 21) -#define LOG_SSP_WRITES (1U << 22) -#define LOG_TIMER_WRITES (1U << 23) -#define LOG_BUZZER_WRITES (1U << 24) -#define LOG_RTC_WRITES (1U << 25) -#define LOG_GPIO_WRITES (1U << 26) -#define LOG_PIN_WRITES (1U << 27) -#define LOG_KBD_WRITES (1U << 28) - -#define LOG_WRITES (LOG_DRAM_WRITES | LOG_LCD_WRITES | LOG_POWER_WRITES | LOG_EOI_WRITES | LOG_INT_WRITES | LOG_CODEC_WRITES \ - | LOG_SSP_WRITES | LOG_TIMER_WRITES | LOG_BUZZER_WRITES | LOG_RTC_WRITES | LOG_GPIO_WRITES | LOG_PIN_WRITES | LOG_KBD_WRITES) -#define LOG_READS (LOG_DRAM_READS | LOG_LCD_READS | LOG_POWER_READS | LOG_EOI_READS | LOG_INT_READS | LOG_CODEC_READS \ - | LOG_SSP_READS | LOG_TIMER_READS | LOG_BUZZER_READS | LOG_RTC_READS | LOG_GPIO_READS | LOG_KBD_READS) -#define LOG_ALL_IRQ (LOG_IRQ | LOG_EOI_WRITES | LOG_INT_WRITES | LOG_EOI_READS | LOG_INT_READS) -#define LOG_ALL (LOG_UNKNOWNS | LOG_IRQ | LOG_DISPLAY | LOG_WRITES | LOG_READS) - -#define VERBOSE (LOG_CODEC_READS | LOG_CODEC_WRITES | LOG_BUZZER_WRITES) -#include "logmacro.h" - -void psion5mx_state::machine_start() -{ - save_item(NAME(m_memcfg)); - save_item(NAME(m_dramcfg)); - - save_item(NAME(m_timer_reload)); - save_item(NAME(m_timer_value)); - save_item(NAME(m_timer_ctrl)); - - save_item(NAME(m_pending_ints)); - save_item(NAME(m_int_mask)); - - save_item(NAME(m_lcd_display_base_addr)); - - save_item(NAME(m_rtc)); - save_item(NAME(m_pwrsr)); - save_item(NAME(m_last_ssi_request)); - save_item(NAME(m_ssi_read_counter)); - - save_item(NAME(m_kbd_scan)); +#include "emu.h" +#include "codec.h" +#include "etna.h" +#include "windermere.h" - save_item(NAME(m_ports)); - - m_timers[0] = timer_alloc(FUNC(psion5mx_state::update_timer1), this); - m_timers[1] = timer_alloc(FUNC(psion5mx_state::update_timer2), this); - m_periodic = timer_alloc(FUNC(psion5mx_state::update_periodic_irq), this); - m_rtc_ticker = timer_alloc(FUNC(psion5mx_state::update_rtc), this); -} - -void psion5mx_state::machine_reset() -{ - std::fill(std::begin(m_memcfg), std::end(m_memcfg), 0); - m_dramcfg = 0; - - m_timers[0]->adjust(attotime::never); - m_timers[1]->adjust(attotime::never); - m_timer_reload[0] = m_timer_reload[1] = 0; - m_timer_ctrl[0] = m_timer_ctrl[1] = 0; - - m_pending_ints = 0; - m_int_mask = 0; - - m_lcd_display_base_addr = 0; - - m_rtc = time(nullptr) - 946684800; - m_pwrsr = (1 << 10) | (1 << 13); - m_last_ssi_request = 0; - m_ssi_read_counter = 0; - m_kbd_scan = 0; +#include "bus/pccard/ataflash.h" +#include "cpu/arm7/arm7.h" +#include "imagedev/snapquik.h" +//#include "machine/bq2018.h" +#include "machine/eepromser.h" +#include "machine/intelfsh.h" +#include "machine/nvram.h" +#include "machine/ram.h" +#include "sound/spkrdev.h" - std::fill(std::begin(m_ports), std::end(m_ports), 0); +#include "emupal.h" +#include "screen.h" +#include "speaker.h" - m_periodic->adjust(attotime::from_hz(64), 0, attotime::from_hz(64)); - m_rtc_ticker->adjust(attotime::from_hz(64), 0, attotime::from_hz(64)); -} +namespace { -void psion5mx_state::check_interrupts() +class psion5mx_state : public driver_device { - LOGMASKED(LOG_IRQ, "Pending FIQs is %08x & %08x & %08x\n", m_pending_ints, m_int_mask, IRQ_FIQ_MASK); - LOGMASKED(LOG_IRQ, "Pending IRQs is %08x & %08x & %08x\n", m_pending_ints, m_int_mask, IRQ_IRQ_MASK); - bool any_interrupts = (m_pending_ints & m_int_mask) != 0; - if (any_interrupts) +public: + psion5mx_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_windermere(*this, "windermere") + , m_etna(*this, "etna") + , m_pccard(*this, "pccard") + , m_ram(*this, "ram") + , m_nvram(*this, "nvram") + , m_eeprom(*this, "eeprom") + , m_screen(*this, "screen") + , m_palette(*this, "palette") + , m_buzzer(*this, "buzzer") + , m_codec(*this, "codec") + , m_mic(*this, "mic") + , m_touchx(*this, "TOUCHX") + , m_touchy(*this, "TOUCHY") + , m_touch(*this, "TOUCH") + , m_kbd_cols(*this, "COL%u", 0U) { - m_maincpu->resume(SUSPEND_REASON_HALT); } - m_maincpu->set_input_line(arm7_cpu_device::ARM7_FIRQ_LINE, m_pending_ints & m_int_mask & IRQ_FIQ_MASK ? ASSERT_LINE : CLEAR_LINE); - m_maincpu->set_input_line(arm7_cpu_device::ARM7_IRQ_LINE, m_pending_ints & m_int_mask & IRQ_IRQ_MASK ? ASSERT_LINE : CLEAR_LINE); -} -TIMER_CALLBACK_MEMBER(psion5mx_state::update_timer1) + void psion5mx(machine_config &config) ATTR_COLD; + void psion5mxp(machine_config &config) ATTR_COLD; + void revo(machine_config &config) ATTR_COLD; + void revoplus(machine_config &config) ATTR_COLD; + + void init_s5mx() ATTR_COLD; + void init_mc218() ATTR_COLD; + void init_revo() ATTR_COLD; + + DECLARE_INPUT_CHANGED_MEMBER(touch_down); + + DECLARE_QUICKLOAD_LOAD_MEMBER(quickload_cb); + +protected: + virtual void machine_start() override ATTR_COLD; + virtual void machine_reset() override ATTR_COLD; + +private: + void palette_init(palette_device &palette) const ATTR_COLD; + + void s5mx_map(address_map &map) ATTR_COLD; + void s5mxp_map(address_map &map) ATTR_COLD; + void revo_map(address_map &map) ATTR_COLD; + + void init_eeprom(std::string type, uint8_t locale = 0xff, uint8_t lang = 0xff); + + uint8_t keyboard_r(); + void portb_w(uint8_t data); + void portd_w(uint8_t data); + uint16_t ads7843_r(offs_t offset); + uint8_t etna_porta_r(); + void etna_porta_w(uint8_t data); + void update_amp(); + + required_device<arm710t_cpu_device> m_maincpu; + required_device<windermere_device> m_windermere; + optional_device<etna_device> m_etna; + optional_device<pccard_slot_device> m_pccard; + required_device<ram_device> m_ram; + required_device<nvram_device> m_nvram; + required_device<eeprom_serial_93cxx_device> m_eeprom; + required_device<screen_device> m_screen; + required_device<palette_device> m_palette; + required_device<speaker_sound_device> m_buzzer; + required_device<psion_codec_device> m_codec; + optional_device<microphone_device> m_mic; + required_ioport m_touchx; + required_ioport m_touchy; + required_ioport m_touch; + required_ioport_array<8> m_kbd_cols; + + uint8_t m_kbd_scan = 0; + uint8_t m_volume = 0; + bool m_amp_enable = true; +}; + + +void psion5mx_state::init_eeprom(std::string machine, uint8_t locale, uint8_t lang) { - update_timer(0); - if (BIT(m_buzzer_ctrl, 1)) + uint8_t *eeprom = memregion("eeprom")->base(); + + // defaults expected by the touchscreen code + eeprom[0x0a] = 20; + eeprom[0x0b] = 20; + eeprom[0x0c] = 20; + eeprom[0x0d] = 30; + + // machine serial + eeprom[0x18] = 0xef; + eeprom[0x19] = 0xbe; + eeprom[0x1a] = 0xad; + eeprom[0x1b] = 0xde; + + // machine type + eeprom[0x28] = machine.length(); + if (machine.length() > 0) { - m_speaker->level_w(BIT(m_timer_value[0], 15)); + const char *key = "PSIONPSIONPSION"; + for (int i = 0; i < 16; i++) + eeprom[0x29 + i] = (i < machine.length()) ? machine[i] ^ key[i] : key[i]; } -} - -TIMER_CALLBACK_MEMBER(psion5mx_state::update_timer2) -{ - update_timer(1); -} -TIMER_CALLBACK_MEMBER(psion5mx_state::update_periodic_irq) -{ - LOGMASKED(LOG_IRQ, "Flagging periodic IRQ\n"); - m_pending_ints |= (1 << IRQ_TINT); - check_interrupts(); -} - -TIMER_CALLBACK_MEMBER(psion5mx_state::update_rtc) -{ - if ((m_pwrsr & 0x3f) == 0x3f) + // language (5mx Pro only) + if (lang != 0xff) { - m_rtc++; - m_pwrsr &= ~0x3f; + eeprom[0x38] = lang; + eeprom[0x39] = lang; } - else + + // localisation (Revo only) + if (locale != 0xff) { - m_pwrsr++; + eeprom[0x3a] = locale; + eeprom[0x3b] = locale; } + + // calculate the checksum + uint8_t chksum = 0; + for (int i = 1; i < 0x80; i++) + chksum ^= eeprom[i]; + + // EPOC is expecting 0x42 + eeprom[0x00] = chksum ^ 0x42; } -void psion5mx_state::update_timer(int timer) +void psion5mx_state::init_s5mx() { - m_timer_value[timer]--; - if (m_timer_value[timer] == 0) - { - LOGMASKED(LOG_IRQ, "Flagging Timer %d IRQ\n", timer + 1); - m_pending_ints |= (1 << (IRQ_TC1OI + timer)); - check_interrupts(); - if (BIT(m_timer_ctrl[timer], 6)) - { - m_timer_value[timer] = m_timer_reload[timer]; - } - } + const std::string &name = machine().basename(); + uint8_t lang = 0x00; + + if (name == "psion5mxp_de") lang = 0x03; // German bootloader (other languages are supported) + + init_eeprom("SERIES5mx", 0xff, lang); } -void psion5mx_state::set_timer_ctrl(int timer, uint32_t value) +void psion5mx_state::init_mc218() { - const uint32_t old = m_timer_ctrl[timer]; - const uint32_t changed = old ^ value; - m_timer_ctrl[timer] = value; - if (changed != 0) - { - attotime interval = BIT(m_timer_ctrl[timer], 3) ? attotime::from_ticks(1, 512000) : attotime::from_ticks(1, 2000); - if (BIT(old, 7) && BIT(value, 7)) - { - m_timers[timer]->adjust(m_timers[timer]->remaining(), 0, interval); - } - else if (BIT(value, 7)) - { - m_timers[timer]->adjust(interval, 0, interval); - } - else - { - m_timers[timer]->adjust(attotime::never); - } - } + const std::string &name = machine().basename(); + uint8_t lang = 0x00; + + if (name == "mc218") lang = 0x01; // not sure why UK version sets this + + init_eeprom("Ericsson MC 218", 0xff, lang); } -uint32_t psion5mx_state::periphs_r(offs_t offset, uint32_t mem_mask) +void psion5mx_state::init_revo() { - const uint32_t reg = offset << 2; - uint32_t data = 0; - switch (reg) - { - case REG_MEMCFG1: - data = m_memcfg[0]; - LOGMASKED(LOG_DRAM_READS, "%s: peripheral read, MEMCFG1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_MEMCFG2: - data = m_memcfg[1]; - LOGMASKED(LOG_DRAM_READS, "%s: peripheral read, MEMCFG2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + const std::string &name = machine().basename(); + uint8_t locale = 0xf0; // default locale - case REG_DRAMCFG: - data = m_dramcfg; - LOGMASKED(LOG_DRAM_READS, "%s: peripheral read, DRAMCFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + if (name == "mako") locale = 0xf2; // set locale to USA - case REG_LCDCTL: - LOGMASKED(LOG_LCD_READS, "%s: peripheral read, LCDCTL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDST: - LOGMASKED(LOG_LCD_READS, "%s: peripheral read, LCDST = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCD_DBAR1: - data = m_lcd_display_base_addr; - LOGMASKED(LOG_LCD_READS, "%s: peripheral read, LCD_DBAR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDT0: - LOGMASKED(LOG_LCD_READS, "%s: peripheral read, LCDT0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDT1: - LOGMASKED(LOG_LCD_READS, "%s: peripheral read, LCDT1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDT2: - LOGMASKED(LOG_LCD_READS, "%s: peripheral read, LCDT2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + init_eeprom("", locale); // machine 'REVO' is read from ROM +} - case REG_PWRSR: - data = m_pwrsr; - LOGMASKED(LOG_POWER_READS, "%s: peripheral read, PWRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PWRCNT: - LOGMASKED(LOG_POWER_READS, "%s: peripheral read, PWRCNT = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_HALT: - LOGMASKED(LOG_POWER_READS, "%s: peripheral read, HALT = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_STBY: - LOGMASKED(LOG_POWER_READS, "%s: peripheral read, STBY = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_BLEOI: - LOGMASKED(LOG_EOI_READS, "%s: peripheral read, BLEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_MCEOI: - LOGMASKED(LOG_EOI_READS, "%s: peripheral read, MCEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TEOI: - LOGMASKED(LOG_EOI_READS, "%s: peripheral read, TEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_STFCLR: - LOGMASKED(LOG_POWER_READS, "%s: peripheral read, STFCLR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_E2EOI: - LOGMASKED(LOG_EOI_READS, "%s: peripheral read, E2EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTSR: - data = m_pending_ints & m_int_mask; - LOGMASKED(LOG_INT_READS, "%s: peripheral read, INTSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTRSR: - data = m_pending_ints; - LOGMASKED(LOG_INT_READS, "%s: peripheral read, INTRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTENS: - data = m_int_mask; - LOGMASKED(LOG_INT_READS, "%s: peripheral read, INTENS = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTENC: - LOGMASKED(LOG_INT_READS, "%s: peripheral read, INTENC = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTTEST1: - LOGMASKED(LOG_INT_READS, "%s: peripheral read, INTTEST1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTTEST2: - LOGMASKED(LOG_INT_READS, "%s: peripheral read, INTTEST2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +void psion5mx_state::machine_start() +{ + // install ROM (mirroring is essential for size detection) + if (!memregion("flash")) // not PRO + { + uint32_t *rom = &memregion("maincpu")->as_u32(); + switch (memregion("maincpu")->bytes()) + { + case 0x1000000: // 16MB region (Series 5mx / MC218) + // install CS0 + m_maincpu->space(AS_PROGRAM).install_rom(0x00000000, 0x007fffff, 0x0f800000, &rom[0]); - case REG_PUMPCON: - LOGMASKED(LOG_POWER_READS, "%s: peripheral read, PUMPCON = %08x & %08x\n", machine().describe_context(), data, mem_mask); + // install CS1 + if (rom[0x3fffff] == 0xffffffff) // 16MB ROM (8MB + 8MB MaskROM) + m_maincpu->space(AS_PROGRAM).install_rom(0x10000000, 0x107fffff, 0x0f800000, &rom[0x200000]); + else if (rom[0x2fffff] == 0xffffffff) // 12MB ROM (8MB + 4MB MaskROM) + m_maincpu->space(AS_PROGRAM).install_rom(0x10000000, 0x103fffff, 0x0fc00000, &rom[0x200000]); + else if (rom[0x27ffff] == 0xffffffff) // 10MB ROM (8MB MaskROM + 2MB Flash) + m_maincpu->space(AS_PROGRAM).install_rom(0x10000000, 0x101fffff, 0x0fe00000, &rom[0x200000]); break; - case REG_CODR: - LOGMASKED(LOG_CODEC_READS, "%s: peripheral read, CODR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_CONFG: - LOGMASKED(LOG_CODEC_READS, "%s: peripheral read, CONFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_COLFG: - LOGMASKED(LOG_CODEC_READS, "%s: peripheral read, COLFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_COEOI: - LOGMASKED(LOG_CODEC_READS | LOG_EOI_READS, "%s: peripheral read, COEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_COTEST: - LOGMASKED(LOG_CODEC_READS, "%s: peripheral read, COTEST = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + case 0x0800000: // 8MB region (Revo) + // install CS0 + m_maincpu->space(AS_PROGRAM).install_rom(0x00000000, 0x003fffff, 0x0fc00000, &rom[0]); - case REG_SSCR0: - LOGMASKED(LOG_SSP_READS, "%s: peripheral read, SSCR0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_SSCR1: - LOGMASKED(LOG_SSP_READS, "%s: peripheral read, SSCR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_SSDR: - { - // TODO: Proper SSP support - uint16_t value = 0; - switch (m_last_ssi_request) - { - case 0xd0d3: // Touch X - value = 50 + (uint16_t)(m_touchx->read() * 5.7); - break; - case 0x9093: // Touch Y - value = 3834 - (uint16_t)(m_touchy->read() * 13.225); - break; - case 0xa4a4: // Main Battery - case 0xe4e4: // Backup Battery - value = 3100; - break; - } - - if (m_ssi_read_counter == 4) data = (value >> 5) & 0x7f; - if (m_ssi_read_counter == 5) data = (value << 3) & 0xf8; - m_ssi_read_counter++; - if (m_ssi_read_counter == 6) m_ssi_read_counter = 0; - - // We should be clearing SSEOTI here, possibly, - // but for now we just leave it on to simplify things - LOGMASKED(LOG_SSP_READS, "%s: peripheral read, SSDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + // install CS1 + m_maincpu->space(AS_PROGRAM).install_rom(0x10000000, 0x103fffff, 0x0fc00000, &rom[0x100000]); break; } - case REG_SSSR: - data = 0; - LOGMASKED(LOG_SSP_READS, "%s: peripheral read, SSSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + } - case REG_TC1LOAD: - data = m_timer_reload[0]; - LOGMASKED(LOG_TIMER_READS, "%s: peripheral read, TC1LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC1VAL: - data = m_timer_value[0]; - LOGMASKED(LOG_TIMER_READS, "%s: peripheral read, TC1VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC1CTRL: - data = m_timer_ctrl[0]; - LOGMASKED(LOG_TIMER_READS, "%s: peripheral read, TC1CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC1EOI: - LOGMASKED(LOG_TIMER_READS | LOG_EOI_READS, "%s: peripheral read, TC1EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC2LOAD: - data = m_timer_reload[1]; - LOGMASKED(LOG_TIMER_READS, "%s: peripheral read, TC2LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC2VAL: - data = m_timer_value[1]; - LOGMASKED(LOG_TIMER_READS, "%s: peripheral read, TC2VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC2CTRL: - data = m_timer_ctrl[1]; - LOGMASKED(LOG_TIMER_READS, "%s: peripheral read, TC2CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC2EOI: - LOGMASKED(LOG_EOI_READS, "%s: peripheral read, TC2EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + // install RAM + m_maincpu->space(AS_PROGRAM).install_ram(0xc0000000, 0xc0000000 + m_ram->mask(), 0x0fffffff ^ m_ram->mask(), m_ram->pointer()); - case REG_BZCONT: - data = m_buzzer_ctrl; - LOGMASKED(LOG_BUZZER_READS, "%s: peripheral read, BZCONT = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + m_nvram->set_base(m_ram->pointer(), m_ram->size()); - case REG_RTCDRL: - data = (uint16_t)m_rtc; - LOGMASKED(LOG_RTC_READS, "%s: peripheral read, RTCDRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_RTCDRU: - data = m_rtc >> 16; - LOGMASKED(LOG_RTC_READS, "%s: peripheral read, RTCDRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_RTCMRL: - LOGMASKED(LOG_RTC_READS, "%s: peripheral read, RTCMRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_RTCMRU: - LOGMASKED(LOG_RTC_READS, "%s: peripheral read, RTCMRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_RTCEOI: - LOGMASKED(LOG_RTC_READS | LOG_EOI_READS, "%s: peripheral read, RTCEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + save_item(NAME(m_kbd_scan)); + save_item(NAME(m_volume)); + save_item(NAME(m_amp_enable)); +} - case REG_PADR: - data = read_keyboard(); - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PADR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PBDR: - data = m_ports[PORTB]; - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PBDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PCDR: - data = m_ports[PORTC]; - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PCDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PDDR: - data = m_ports[PORTD]; - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PADDR: - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PADDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PBDDR: - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PBDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PCDDR: - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PCDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PDDDR: - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PDDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PEDR: - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PEDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PEDDR: - LOGMASKED(LOG_GPIO_READS, "%s: peripheral read, PEDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +void psion5mx_state::machine_reset() +{ + m_kbd_scan = 0; +} - case REG_KSCAN: - data = m_kbd_scan; - LOGMASKED(LOG_KBD_READS, "%s: peripheral read, KSCAN = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDMUX: - LOGMASKED(LOG_LCD_READS, "%s: peripheral read, LCDMUX = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - default: - LOGMASKED(LOG_UNKNOWNS, "%s: peripheral read, Unknown = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +uint8_t psion5mx_state::keyboard_r() +{ + uint8_t data = 0x00; + + for (int i = 0; i < 8; i++) + { + if (BIT(m_kbd_scan, i)) + data |= m_kbd_cols[i]->read(); } + return data; } -void psion5mx_state::periphs_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - const uint32_t reg = offset << 2; - switch (reg) - { - case REG_MEMCFG1: - m_memcfg[0] = data; - LOGMASKED(LOG_DRAM_WRITES, "%s: peripheral write, MEMCFG1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_MEMCFG2: - m_memcfg[1] = data; - LOGMASKED(LOG_DRAM_WRITES, "%s: peripheral write, MEMCFG2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_DRAMCFG: - m_dramcfg = data; - LOGMASKED(LOG_DRAM_WRITES, "%s: peripheral write, DRAMCFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +void psion5mx_state::portb_w(uint8_t data) +{ + m_eeprom->cs_write(BIT(data, 0)); + m_eeprom->clk_write(BIT(data, 1)); +} - case REG_LCDCTL: - LOGMASKED(LOG_LCD_WRITES, "%s: peripheral write, LCDCTL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDST: - LOGMASKED(LOG_LCD_WRITES, "%s: peripheral write, LCDST = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCD_DBAR1: - LOGMASKED(LOG_LCD_WRITES, "%s: peripheral write, LCD_DBAR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - COMBINE_DATA(&m_lcd_display_base_addr); - break; - case REG_LCDT0: - LOGMASKED(LOG_LCD_WRITES, "%s: peripheral write, LCDT0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDT1: - LOGMASKED(LOG_LCD_WRITES, "%s: peripheral write, LCDT1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDT2: - LOGMASKED(LOG_LCD_WRITES, "%s: peripheral write, LCDT2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +void psion5mx_state::portd_w(uint8_t data) +{ + m_codec->pdn_w(BIT(data, 0)); // CODEN - case REG_PWRSR: - COMBINE_DATA(&m_pwrsr); - LOGMASKED(LOG_POWER_WRITES, "%s: peripheral write, PWRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PWRCNT: - LOGMASKED(LOG_POWER_WRITES, "%s: peripheral write, PWRCNT = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_HALT: - m_maincpu->suspend(SUSPEND_REASON_HALT, 1); - LOGMASKED(LOG_POWER_WRITES, "%s: peripheral write, HALT = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_STBY: - LOGMASKED(LOG_POWER_WRITES, "%s: peripheral write, STBY = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_BLEOI: - LOGMASKED(LOG_EOI_WRITES, "%s: peripheral write, BLEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_MCEOI: - LOGMASKED(LOG_EOI_WRITES, "%s: peripheral write, MCEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TEOI: - LOGMASKED(LOG_EOI_WRITES, "%s: peripheral write, TEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_pending_ints &= ~(1 << IRQ_TINT); - check_interrupts(); - break; - case REG_STFCLR: - m_pwrsr &= ~0x00003e00; - LOGMASKED(LOG_POWER_WRITES, "%s: peripheral write, STFCLR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_E2EOI: - LOGMASKED(LOG_EOI_WRITES, "%s: peripheral write, E2EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + m_amp_enable = BIT(data, 1); // AMPEN + update_amp(); +} - case REG_INTSR: - LOGMASKED(LOG_INT_WRITES, "%s: peripheral write, INTSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTRSR: - LOGMASKED(LOG_INT_WRITES, "%s: peripheral write, INTRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTENS: - m_int_mask |= data & mem_mask; - LOGMASKED(LOG_INT_WRITES, "%s: peripheral write, INTENS = %08x & %08x\n", machine().describe_context(), data, mem_mask); - check_interrupts(); - break; - case REG_INTENC: - m_int_mask &= ~(data & mem_mask); - LOGMASKED(LOG_INT_WRITES, "%s: peripheral write, INTENC = %08x & %08x\n", machine().describe_context(), data, mem_mask); - check_interrupts(); - break; - case REG_INTTEST1: - LOGMASKED(LOG_INT_WRITES, "%s: peripheral write, INTTEST1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_INTTEST2: - LOGMASKED(LOG_INT_WRITES, "%s: peripheral write, INTTEST2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PUMPCON: - LOGMASKED(LOG_POWER_WRITES, "%s: peripheral write, PUMPCON = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +uint16_t psion5mx_state::ads7843_r(offs_t offset) +{ + uint16_t data = 0; - case REG_CODR: - LOGMASKED(LOG_CODEC_WRITES, "%s: peripheral write, CODR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_CONFG: - LOGMASKED(LOG_CODEC_WRITES, "%s: peripheral write, CONFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_COLFG: - LOGMASKED(LOG_CODEC_WRITES, "%s: peripheral write, COLFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_COEOI: - LOGMASKED(LOG_CODEC_WRITES | LOG_EOI_WRITES, "%s: peripheral write, COEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_COTEST: - LOGMASKED(LOG_CODEC_WRITES, "%s: peripheral write, COTEST = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + // TODO: Proper SSP support with ADS7843 device + switch (offset) + { + case 0xd0d3: // Touch X + data = 50 + (uint16_t)(m_touchx->read() * 5.7); + break; + case 0x9093: // Touch Y + data = 3834 - (uint16_t)(m_touchy->read() * 13.225); + break; + case 0xa4a4: // Main Battery + case 0xe4e4: // Backup Battery + data = 3100; + break; + } - case REG_SSCR0: - LOGMASKED(LOG_SSP_WRITES, "%s: peripheral write, SSCR0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_SSCR1: - LOGMASKED(LOG_SSP_WRITES, "%s: peripheral write, SSCR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_SSDR: - LOGMASKED(LOG_SSP_WRITES, "%s: peripheral write, SSDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - // TODO: Proper SPI support - if (data != 0) - { - m_last_ssi_request = (m_last_ssi_request >> 8) | (data & 0xff00); - } - break; - case REG_SSSR: - LOGMASKED(LOG_SSP_WRITES, "%s: peripheral write, SSSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + return data; +} - case REG_TC1LOAD: - LOGMASKED(LOG_TIMER_WRITES, "%s: peripheral write, TC1LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_timer_reload[0] = data; - m_timer_value[0] = data; - break; - case REG_TC1VAL: - LOGMASKED(LOG_TIMER_WRITES, "%s: peripheral write, TC1VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC1CTRL: - LOGMASKED(LOG_TIMER_WRITES, "%s: peripheral write, TC1CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - set_timer_ctrl(0, data); - break; - case REG_TC1EOI: - LOGMASKED(LOG_TIMER_WRITES | LOG_EOI_WRITES, "%s: peripheral write, TC1EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_pending_ints &= ~(1 << IRQ_TC1OI); - check_interrupts(); - break; - case REG_TC2LOAD: - LOGMASKED(LOG_TIMER_WRITES, "%s: peripheral write, TC2LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_timer_reload[1] = data; - m_timer_value[1] = data; - break; - case REG_TC2VAL: - LOGMASKED(LOG_TIMER_WRITES, "%s: peripheral write, TC2VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_TC2CTRL: - LOGMASKED(LOG_TIMER_WRITES, "%s: peripheral write, TC2CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - set_timer_ctrl(1, data); - break; - case REG_TC2EOI: - LOGMASKED(LOG_TIMER_WRITES | LOG_EOI_WRITES, "%s: peripheral write, TC2EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_pending_ints &= ~(1 << IRQ_TC2OI); - check_interrupts(); - break; - case REG_BZCONT: - m_buzzer_ctrl = data; - if (!BIT(m_buzzer_ctrl, 1)) - { - m_speaker->level_w(BIT(m_buzzer_ctrl, 0)); - } - LOGMASKED(LOG_BUZZER_WRITES, "%s: peripheral write, BZCONT = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +uint8_t psion5mx_state::etna_porta_r() +{ + uint8_t data = 0x00; - case REG_RTCDRL: - LOGMASKED(LOG_RTC_WRITES, "%s: peripheral write, RTCDRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_rtc &= 0xffff0000; - m_rtc |= (uint16_t)data; - break; - case REG_RTCDRU: - LOGMASKED(LOG_RTC_WRITES, "%s: peripheral write, RTCDRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_rtc &= 0x0000ffff; - m_rtc |= data << 16; - break; - case REG_RTCMRL: - LOGMASKED(LOG_RTC_WRITES, "%s: peripheral write, RTCMRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_RTCMRU: - LOGMASKED(LOG_RTC_WRITES, "%s: peripheral write, RTCMRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_RTCEOI: - LOGMASKED(LOG_RTC_WRITES | LOG_EOI_WRITES, "%s: peripheral write, RTCEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + data |= m_eeprom->do_read() << 3; - case REG_PADR: - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PADR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - m_ports[PORTA] = data; - break; - case REG_PBDR: - { - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PBDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - const uint8_t old = m_ports[PORTB]; - m_ports[PORTB] = data; - const uint8_t diff = old ^ data; - if (BIT(diff, 0)) - m_etna->eeprom_cs_in(BIT(data, 0)); - if (BIT(diff, 1)) - m_etna->eeprom_clk_in(BIT(data, 1)); - if (diff & 0x3c) - LOGMASKED(LOG_PIN_WRITES, "Contrast: %d\n", (data >> 2) & 0x0f); - if (BIT(diff, 6)) - LOGMASKED(LOG_PIN_WRITES, "Case Open: %d\n", BIT(data, 6)); - if (BIT(diff, 7)) - LOGMASKED(LOG_PIN_WRITES, "ETNA CompactFlash Power: %d\n", BIT(data, 7)); - break; - } - case REG_PCDR: - { - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PCDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - const uint8_t old = m_ports[PORTC]; - m_ports[PORTC] = data; - const uint8_t diff = old ^ data; - if (BIT(diff, 0)) - LOGMASKED(LOG_PIN_WRITES, "RS232 RTS: %d\n", BIT(data, 0)); - if (BIT(diff, 1)) - LOGMASKED(LOG_PIN_WRITES, "RS232 DTR Toggle: %d\n", BIT(data, 1)); - if (BIT(diff, 2)) - LOGMASKED(LOG_PIN_WRITES, "Disable Power LED: %d\n", BIT(data, 2)); - if (BIT(diff, 3)) - LOGMASKED(LOG_PIN_WRITES, "Enable UART1: %d\n", BIT(data, 3)); - if (BIT(diff, 4)) - LOGMASKED(LOG_PIN_WRITES, "LCD Backlight: %d\n", BIT(data, 4)); - if (BIT(diff, 5)) - LOGMASKED(LOG_PIN_WRITES, "Enable UART0: %d\n", BIT(data, 5)); - if (BIT(diff, 6)) - LOGMASKED(LOG_PIN_WRITES, "Dictaphone: %d\n", BIT(data, 6)); - break; - } - case REG_PDDR: - { - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - const uint8_t old = m_ports[PORTD]; - m_ports[PORTD] = data; - const uint8_t diff = old ^ data; - if (BIT(diff, 0)) - LOGMASKED(LOG_PIN_WRITES, "Codec Enable: %d\n", BIT(data, 0)); - if (BIT(diff, 1)) - LOGMASKED(LOG_PIN_WRITES, "Audio Amp Enable: %d\n", BIT(data, 1)); - if (BIT(diff, 2)) - LOGMASKED(LOG_PIN_WRITES, "LCD Power: %d\n", BIT(data, 2)); - if (BIT(diff, 3)) - LOGMASKED(LOG_PIN_WRITES, "ETNA Door: %d\n", BIT(data, 3)); - if (BIT(diff, 4)) - LOGMASKED(LOG_PIN_WRITES, "Sled: %d\n", BIT(data, 4)); - if (BIT(diff, 5)) - LOGMASKED(LOG_PIN_WRITES, "Pump Power2: %d\n", BIT(data, 5)); - if (BIT(diff, 6)) - LOGMASKED(LOG_PIN_WRITES, "Pump Power1: %d\n", BIT(data, 6)); - if (BIT(diff, 7)) - LOGMASKED(LOG_PIN_WRITES, "ETNA Error: %d\n", BIT(data, 7)); - break; - } - case REG_PADDR: - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PADDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PBDDR: - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PBDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PCDDR: - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PCDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PDDDR: - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PDDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PEDR: - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PEDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_PEDDR: - LOGMASKED(LOG_GPIO_WRITES, "%s: peripheral write, PEDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; + return data; +} - case REG_KSCAN: - m_kbd_scan = data; - LOGMASKED(LOG_KBD_WRITES, "%s: peripheral write, KSCAN = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - case REG_LCDMUX: - LOGMASKED(LOG_LCD_WRITES, "%s: peripheral write, LCDMUX = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; +void psion5mx_state::etna_porta_w(uint8_t data) +{ + m_volume = data & 3; + update_amp(); - default: - LOGMASKED(LOG_UNKNOWNS, "%s: peripheral write, Unknown = %08x & %08x\n", machine().describe_context(), data, mem_mask); - break; - } + m_eeprom->di_write(BIT(data, 2)); } -uint8_t psion5mx_state::read_keyboard() + +void psion5mx_state::update_amp() { - if (BIT(m_kbd_scan, 3)) + // TODO: MSC1192 speaker amplifier, can be put into standby to mute audio. + static const float codec_volume[4] = { 1.0f, 0.75f, 0.5f, 0.25f }; + + if (m_amp_enable) { - return m_kbd_cols[m_kbd_scan & 7]->read(); + m_buzzer->set_output_gain(ALL_OUTPUTS, 1.0); + m_codec->set_output_gain(ALL_OUTPUTS, codec_volume[m_volume]); // VOL } - else if (m_kbd_scan == 0) + else { - uint8_t rows = 0; - for (int i = 0; i < 8; i++) - { - rows |= m_kbd_cols[i]->read(); - } - return rows; + m_buzzer->set_output_gain(ALL_OUTPUTS, 0.0); + m_codec->set_output_gain(ALL_OUTPUTS, 0.0); } - return 0x00; } -void psion5mx_state::main_map(address_map &map) + +void psion5mx_state::s5mx_map(address_map &map) { - map(0x00000000, 0x009fffff).rom().region("maincpu", 0); map(0x20000000, 0x20000fff).rw(m_etna, FUNC(etna_device::regs_r), FUNC(etna_device::regs_w)); - map(0x80000000, 0x80000fff).rw(FUNC(psion5mx_state::periphs_r), FUNC(psion5mx_state::periphs_w)); - map(0xc0000000, 0xc03fffff).ram().mirror(0x1fc00000).share("lcd_ram"); + map(0x40000000, 0x43ffffff).rw(m_pccard, FUNC(pccard_slot_device::read_reg), FUNC(pccard_slot_device::write_reg)); + map(0x44000000, 0x47ffffff).rw(m_pccard, FUNC(pccard_slot_device::read_memory), FUNC(pccard_slot_device::write_memory)); + map(0x80000000, 0x80000fff).rw(m_windermere, FUNC(windermere_device::periphs_r), FUNC(windermere_device::periphs_w)); } -void psion5mx_state::palette_init(palette_device &palette) +void psion5mx_state::s5mxp_map(address_map &map) { - for (int i = 0; i < 16; i++) - { - const int r = (0x99 * i) / 15; - const int g = (0xaa * i) / 15; - const int b = (0x88 * i) / 15; - m_palette->set_pen_color(15 - i, rgb_t(r, g, b)); - } + map(0x00000000, 0x0001ffff).rw("flash", FUNC(intelfsh8_device::read), FUNC(intelfsh8_device::write)); + map(0x20000000, 0x20000fff).rw(m_etna, FUNC(etna_device::regs_r), FUNC(etna_device::regs_w)); + map(0x40000000, 0x43ffffff).rw(m_pccard, FUNC(pccard_slot_device::read_reg), FUNC(pccard_slot_device::write_reg)); + map(0x44000000, 0x47ffffff).rw(m_pccard, FUNC(pccard_slot_device::read_memory), FUNC(pccard_slot_device::write_memory)); + map(0x80000000, 0x80000fff).rw(m_windermere, FUNC(windermere_device::periphs_r), FUNC(windermere_device::periphs_w)); } -uint32_t psion5mx_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +void psion5mx_state::revo_map(address_map &map) { - const uint8_t *lcd_buf = (uint8_t*)&m_lcd_ram[(m_lcd_display_base_addr & 0x003fffff) >> 2]; - static const int width = 640; - static const int height = 240; + map(0x80000000, 0x80000fff).rw(m_windermere, FUNC(windermere_device::periphs_r), FUNC(windermere_device::periphs_w)); +} - // fetch palette - LOGMASKED(LOG_DISPLAY, "%02x %02x %02x %02x\n", lcd_buf[0], lcd_buf[1], lcd_buf[2], lcd_buf[3]); - const int bpp = 1 << (lcd_buf[1] >> 4); - const int ppb = 8 / bpp; - LOGMASKED(LOG_DISPLAY, "bpp: %d, ppb: %d\n", bpp, ppb); - uint16_t palette[16] = {}; +void psion5mx_state::palette_init(palette_device &palette) const +{ for (int i = 0; i < 16; i++) { - palette[i] = lcd_buf[i*2] | ((lcd_buf[i*2+1] << 8) & 0xf00); - LOGMASKED(LOG_DISPLAY, "palette[%d]: %04x\n", i, palette[i]); - } - - const pen_t *pen = m_palette->pens(); - - // build our image out - const int line_width = (width * bpp) / 8; - for (int y = 0; y < height; y++) - { - const int line_offs = 0x20 + (line_width * y); - uint32_t *line = &bitmap.pix(y); - for (int x = 0; x < width; x++) - { - const uint8_t byte = lcd_buf[line_offs + (x / ppb)]; - const int shift = (x & (ppb - 1)) * bpp; - const int mask = (1 << bpp) - 1; - const int pal_idx = (byte >> shift) & mask; - - line[x] = pen[palette[pal_idx]]; - } + const int r = (0x99 * i) / 15; + const int g = (0xaa * i) / 15; + const int b = (0x88 * i) / 15; + m_palette->set_pen_color(15 - i, rgb_t(r, g, b)); } - return 0; } + INPUT_CHANGED_MEMBER(psion5mx_state::touch_down) { - if (newval) - { - logerror("Flagging EINT3\n"); - m_pending_ints |= (1 << IRQ_EINT3); - } - else - { - logerror("Unflagging EINT3\n"); - m_pending_ints &= ~(1 << IRQ_EINT3); - } - check_interrupts(); + m_windermere->eint3_w(newval ? ASSERT_LINE : CLEAR_LINE); } -/* Input ports */ INPUT_PORTS_START( psion5mx ) PORT_START("TOUCHX") - PORT_BIT(0x3ff, 362, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_MINMAX(42,681) PORT_SENSITIVITY(25) PORT_KEYDELTA(13) + PORT_BIT(0x3ff, 362, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_MINMAX(0,694) PORT_SENSITIVITY(25) PORT_KEYDELTA(13) PORT_START("TOUCHY") - PORT_BIT(0x0ff, 125, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(5,244) PORT_SENSITIVITY(25) PORT_KEYDELTA(13) + PORT_BIT(0x1ff, 125, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_MINMAX(0,279) PORT_SENSITIVITY(25) PORT_KEYDELTA(13) PORT_START("TOUCH") PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Touch") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(psion5mx_state::touch_down), 0) PORT_BIT(0xfffe, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL0") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6") PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') PORT_CHAR('>') - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CHAR('<') - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4") PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('@') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(163) PORT_CHAR('\\') - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2") PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_CHAR('#') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1") PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_CHAR('_') - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Dictaphone Record") PORT_CODE(KEYCODE_INSERT) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') PORT_CHAR('>') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CHAR('<') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('@') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(163) PORT_CHAR('\\') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_CHAR('#') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_CHAR('_') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_INSERT) PORT_NAME("Dictaphone Record") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL1") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("'") PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('~') PORT_CHAR(':') - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Del<-") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_CHAR('}') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9") PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_CHAR('{') - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8") PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') PORT_CHAR(']') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7") PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_CHAR('[') - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Dictaphone Play") PORT_CODE(KEYCODE_HOME) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('\'') PORT_CHAR('~') PORT_CHAR(':') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_NAME("Del<-") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_CHAR('}') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_CHAR('{') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') PORT_CHAR(']') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_CHAR('[') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_NAME("Dictaphone Play") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL2") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(128) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(128) + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) PORT_NAME("Esc") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL3") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(';') - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR('=') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR('-') - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR('+') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Menu") PORT_CODE(KEYCODE_END) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("Enter") + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(';') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR('=') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR('-') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR('+') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_END) PORT_NAME("Menu") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL4") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) PORT_NAME("Tab Caps") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Ctrl") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL5") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('?') - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Fn") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME(u8"\u2193") // U+2193 = ↓ + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('?') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("Fn") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL6") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_NAME("Right Shift") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START("COL7") - PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) - PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) - PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('/') - PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) - PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') - PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Dictaphone Stop") PORT_CODE(KEYCODE_PGUP) - PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME(u8"\u2192") // U+2192 = → + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME(u8"\u2190") // U+2190 = ← + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('/') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME(u8"\u2191") // U+2191 = ↑ + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_NAME("Space") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PGUP) PORT_NAME("Dictaphone Stop") + PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Left Shift") PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_UNUSED) INPUT_PORTS_END -/* basic configuration for 2 lines display */ +INPUT_PORTS_START( psion5mx_de ) + PORT_INCLUDE(psion5mx) + + PORT_MODIFY("COL2") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('z') PORT_CHAR('Z') + + PORT_MODIFY("COL6") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('y') PORT_CHAR('Y') +INPUT_PORTS_END + +INPUT_PORTS_START( psion5mx_fr ) + PORT_INCLUDE(psion5mx) + + PORT_MODIFY("COL2") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('a') PORT_CHAR('A') + + PORT_MODIFY("COL4") + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('q') PORT_CHAR('Q') + + PORT_MODIFY("COL6") + PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('w') PORT_CHAR('W') +INPUT_PORTS_END + +//INPUT_PORTS_START( psion5mx_us ) +// PORT_INCLUDE(psion5mx) +// +// PORT_MODIFY("COL0") +// PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('/') +// PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_CHAR('\\') +// PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') PORT_CHAR('~') +//INPUT_PORTS_END + +INPUT_PORTS_START( revo ) + PORT_INCLUDE(psion5mx) + + PORT_MODIFY("COL0") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('~') + + PORT_MODIFY("COL1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('\'') PORT_CHAR('@') PORT_CHAR(':') +INPUT_PORTS_END + +INPUT_PORTS_START( revo_us ) + PORT_INCLUDE(psion5mx) + + PORT_MODIFY("COL0") + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('/') + PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_CHAR('\\') + PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') PORT_CHAR('~') + + PORT_MODIFY("COL1") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') PORT_CHAR('"') PORT_CHAR(';') +INPUT_PORTS_END + + +QUICKLOAD_LOAD_MEMBER(psion5mx_state::quickload_cb) +{ + // load the OS image as a ROM (this would normally be loaded from CF by the bootloader) + uint8_t *rom = memregion("maincpu")->base(); + image.fread(rom, image.length()); + m_maincpu->space(AS_PROGRAM).install_rom(0x00000000, 0x00ffffff, 0x0f000000, rom); + + machine().schedule_soft_reset(); + + return std::make_pair(std::error_condition(), std::string()); +} + + +static void pcmcia_devices(device_slot_interface &device) +{ + device.option_add("cf", ATA_FLASH_PCCARD); +} + + void psion5mx_state::psion5mx(machine_config &config) { - /* basic machine hardware */ - ARM710T(config, m_maincpu, 36000000); // 36MHz, per wikipedia - m_maincpu->set_addrmap(AS_PROGRAM, &psion5mx_state::main_map); + ARM710T(config, m_maincpu, 3.6864_MHz_XTAL * 10); + m_maincpu->set_addrmap(AS_PROGRAM, &psion5mx_state::s5mx_map); + + WINDERMERE(config, m_windermere, 3.6864_MHz_XTAL, m_maincpu); + m_windermere->lcd_dma_cb().set(m_ram, FUNC(ram_device::read)); + m_windermere->porta_r().set(FUNC(psion5mx_state::keyboard_r)); + m_windermere->portb_w().set(FUNC(psion5mx_state::portb_w)); + //m_windermere->portc_w().set(m_eeprom, FUNC(eeprom_serial_93cxx_device::pre_write)).bit(7); + m_windermere->portd_w().set(FUNC(psion5mx_state::portd_w)); + m_windermere->pcm_in().set(m_codec, FUNC(psion_codec_device::pcm_out)); + m_windermere->pcm_out().set(m_codec, FUNC(psion_codec_device::pcm_in)); + m_windermere->buz_cb().set(m_buzzer, FUNC(speaker_sound_device::level_w)); + m_windermere->col_cb().set([this](uint8_t data) { m_kbd_scan = data; }); + m_windermere->ssp_r().set(FUNC(psion5mx_state::ads7843_r)); + m_windermere->set_screen_origin(45, 5); + m_windermere->set_screen("screen"); + + //ADS7843(config, "adc", 0); + + RAM(config, m_ram).set_default_size("16M"); + NVRAM(config, "nvram", nvram_device::DEFAULT_NONE); ETNA(config, m_etna); - - /* video hardware */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); - screen.set_refresh_hz(60); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); /* not accurate */ - screen.set_screen_update(FUNC(psion5mx_state::screen_update)); - screen.set_size(640, 240); - screen.set_visarea(0, 640-1, 0, 240-1); + m_etna->porta_r().set(FUNC(psion5mx_state::etna_porta_r)); + m_etna->porta_w().set(FUNC(psion5mx_state::etna_porta_w)); + + PCCARD_SLOT(config, m_pccard, pcmcia_devices, "cf").set_fixed(true); + //m_pccard->cd1().set(m_etna, FUNC(etna_device::write_pc1_cd1)); + //m_pccard->cd2().set(m_etna, FUNC(etna_device::write_pc1_cd2)); + //m_pccard->bvd1().set(m_etna, FUNC(etna_device::write_pc1_bvd1)); + //m_pccard->bvd2().set(m_etna, FUNC(etna_device::write_pc1_bvd2)); + //m_pccard->wp().set(m_etna, FUNC(etna_device::write_pc1_wp)); + + SCREEN(config, m_screen, SCREEN_TYPE_LCD); + m_screen->set_refresh_hz(60); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(0)); + m_screen->set_screen_update(m_windermere, FUNC(windermere_device::screen_update)); + m_screen->set_size(695, 280); // PEN 695x280 LCD 640x240 + m_screen->set_visarea_full(); + m_screen->set_palette(m_palette); PALETTE(config, m_palette, FUNC(psion5mx_state::palette_init), 16); - /* sound hardware */ + PSION_CODEC(config, m_codec, 8000).add_route(ALL_OUTPUTS, "mono", 1.0); // TODO: MSM7717 + SPEAKER(config, "mono").front_center(); - SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00); + SPEAKER_SOUND(config, m_buzzer).add_route(ALL_OUTPUTS, "mono", 1.0); + + MICROPHONE(config, m_mic, 1).front_center(); + m_mic->add_route(0, m_codec, 1.0); + + EEPROM_93C46_16BIT(config, m_eeprom); // 93CS46 +} + + +void psion5mx_state::psion5mxp(machine_config &config) +{ + psion5mx(config); + + m_maincpu->set_addrmap(AS_PROGRAM, &psion5mx_state::s5mxp_map); + + m_ram->set_default_size("32M"); + + ATMEL_29C010(config, "flash"); // 29LV010 + + quickload_image_device &quickload(QUICKLOAD(config, "quickload", "bin")); + quickload.set_load_callback(FUNC(psion5mx_state::quickload_cb)); + quickload.set_interface("psion_quik"); + + SOFTWARE_LIST(config, "quik_ls").set_original("psion_quik").set_filter("PRO"); +} + + +void psion5mx_state::revo(machine_config &config) +{ + psion5mx(config); + + config.device_remove("etna"); + config.device_remove("pccard"); + config.device_remove("mic"); + + m_maincpu->set_addrmap(AS_PROGRAM, &psion5mx_state::revo_map); + + m_windermere->set_screen_origin(37, 5); + //m_windermere->portd_r().set("pm", FUNC(bq2018_device::hdq_r)).lshift(7); + //m_windermere->portd_w().set("pm", FUNC(bq2018_device::hdq_w)).bit(7); + m_windermere->porte_r().set(FUNC(psion5mx_state::etna_porta_r)); + m_windermere->porte_w().set(FUNC(psion5mx_state::etna_porta_w)); + + m_ram->set_default_size("8M").set_extra_options("16M"); // Revo = 8MB, Revo Plus = 16MB + + m_screen->set_size(527, 208); // PEN 527x208 LCD 480x160 + m_screen->set_visarea_full(); + + //BQ2018(config, "pm"); +} + + +void psion5mx_state::revoplus(machine_config &config) +{ + revo(config); + + m_ram->set_default_size("16M"); } -/* ROM definition */ ROM_START( psion5mx ) - ROM_REGION( 0xa00000, "maincpu", 0 ) - ROM_LOAD( "5mx.rom", 0x000000, 0xa00000, CRC(a1e2d038) SHA1(4c082321264e1ae7fe77699e59b8960460690fa6) ) + ROM_REGION32_LE(0x1000000, "maincpu", ROMREGION_ERASE00) + ROM_SYSTEM_BIOS(0, "260", "V1.05(260) 16M") + ROMX_LOAD("s5mx_uk16_v260.rom", 0x0000000, 0x1000000, CRC(3b25a6a4) SHA1(8d67b5ed347bd6e202d6dda26c5752c87dc805e5), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "255", "V1.05(255) 16M") + ROMX_LOAD("s5mx_uk16_v255.rom", 0x0000000, 0x1000000, CRC(c3a7486c) SHA1(9120d8f209d8763adfbab89a39c02cfd4ebf5c26), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "255a", "V1.05(255)") + ROMX_LOAD("s5mx_uk10_v255.rom", 0x0000000, 0x0a00000, CRC(a1e2d038) SHA1(4c082321264e1ae7fe77699e59b8960460690fa6), ROM_BIOS(2)) + ROM_SYSTEM_BIOS(3, "250", "V1.05(250)") + ROMX_LOAD("s5mx_uk10_v250.rom", 0x0000000, 0x0a00000, CRC(31f02326) SHA1(0ea2e3131f5cb2c105b4d5ec3bfafbf5e9e31a89), ROM_BIOS(3)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASE00) +ROM_END + +ROM_START( psion5mx_fr ) + ROM_REGION32_LE(0x1000000, "maincpu", ROMREGION_ERASE00) + ROM_SYSTEM_BIOS(0, "315", "V1.05(315) 16M") + ROMX_LOAD("s5mx_fr16_v315.rom", 0x0000000, 0x1000000, CRC(8473d78c) SHA1(8e4284da7a2060d60c8dfc42357a730849f459cb), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "292", "V1.05(292)") + ROMX_LOAD("s5mx_fr10_v292.rom", 0x0000000, 0x0a00000, CRC(36798a40) SHA1(2e84c690e462858c571f5651fc8e258043b4fe8b), ROM_BIOS(1)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASE00) +ROM_END + +ROM_START( psion5mxp ) + ROM_REGION32_LE(0x1000000, "maincpu", ROMREGION_ERASE00) + + ROM_REGION(0x20000, "flash", 0) + ROM_LOAD("s5mx_blge_v109.bin", 0x0000, 0x20000, BAD_DUMP CRC(95b6d2b0) SHA1(cd65a0dd904954759cf900b67f4e4edf59496c0a)) // UK version not verified as being same as German + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASE00) +ROM_END + +ROM_START( psion5mxp_de ) + ROM_REGION32_LE(0x1000000, "maincpu", ROMREGION_ERASE00) + + ROM_REGION(0x20000, "flash", 0) + ROM_SYSTEM_BIOS(0, "109", "Bootloader V1.09") + ROMX_LOAD("s5mx_blge_v109.bin", 0x0000, 0x20000, CRC(95b6d2b0) SHA1(cd65a0dd904954759cf900b67f4e4edf59496c0a), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "108", "Bootloader V1.08") + ROMX_LOAD("s5mx_blge_v108.bin", 0x0000, 0x20000, CRC(18a7be84) SHA1(cd65a0dd904954759cf900b67f4e4edf59496c0a), ROM_BIOS(1)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASE00) ROM_END -/* Driver */ +ROM_START( mc218 ) + ROM_REGION32_LE(0x1000000, "maincpu", ROMREGION_ERASE00) + ROM_SYSTEM_BIOS(0, "259", "V1.05(259)") + ROMX_LOAD("mc218_uk12_v259.rom", 0x0000000, 0x0c00000, CRC(92f353b5) SHA1(f6ff73bdd59457e449f1faf95fe73878b3a94d8c), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "256", "V1.05(256)") + ROMX_LOAD("mc218_uk12_v256.rom", 0x0000000, 0x0c00000, CRC(616d0b54) SHA1(77dcd44dc6a26654f52c0ced07db0f505c896b48), ROM_BIOS(1)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASE00) +ROM_END + +ROM_START( mc218_de ) + ROM_REGION32_LE(0x1000000, "maincpu", ROMREGION_ERASE00) + ROM_SYSTEM_BIOS(0, "260", "V1.05(260)") + ROMX_LOAD("mc218_de12_v260.rom", 0x0000000, 0x0c00000, CRC(6d4835ff) SHA1(917071175c6632f3ff7061ff93d30b681b58f3d6), ROM_BIOS(0)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASE00) +ROM_END + +ROM_START( mc218_fr ) + ROM_REGION32_LE(0x1000000, "maincpu", ROMREGION_ERASE00) + ROM_SYSTEM_BIOS(0, "262", "V1.05(262)") + ROMX_LOAD("mc218_fr12_v262.rom", 0x0000000, 0x0c00000, CRC(e00f8b67) SHA1(5de1896615e916bb5ddf84820678c317fcbfb820), ROM_BIOS(0)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASE00) +ROM_END + +ROM_START( revo ) + ROM_REGION32_LE(0x800000, "maincpu", 0) + ROM_SYSTEM_BIOS(0, "390", "V1.06(390)") + ROMX_LOAD("revo_ukus8_v390.rom", 0x000000, 0x800000, CRC(846c8176) SHA1(297c18621ea6c9440e74c71cc1cb58f21fe46796), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "361", "V1.06(361)") + ROMX_LOAD("revo_ukus8_v361.rom", 0x000000, 0x800000, CRC(2418a352) SHA1(dc03eec968b1d503fd389999db3ef2070793b507), ROM_BIOS(1)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASEFF) +ROM_END + +ROM_START( revo_de ) + ROM_REGION32_LE(0x800000, "maincpu", 0) + ROM_SYSTEM_BIOS(0, "391", "V1.06(391)") + ROMX_LOAD("revo_de8_v391.rom", 0x000000, 0x800000, CRC(e627747f) SHA1(3f451b7b0e738ee581bf73e1db310605d407e218), ROM_BIOS(0)) + ROM_SYSTEM_BIOS(1, "369", "V1.06(369)") + ROMX_LOAD("revo_de8_v369.rom", 0x000000, 0x800000, CRC(1935958f) SHA1(bfe02a1817fb98ef24176b09e1c67b81c7235473), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(2, "352", "V1.06(352)") + ROMX_LOAD("revo_de8_v352.rom", 0x000000, 0x800000, CRC(100f6567) SHA1(1b79f66b2cf8bc87304377112d9bcad4dd59891c), ROM_BIOS(2)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASEFF) +ROM_END + +ROM_START( revo_fr ) + ROM_REGION32_LE(0x800000, "maincpu", 0) + ROM_SYSTEM_BIOS(0, "392", "V1.06(392)") + ROMX_LOAD("revo_fr8_v392.rom", 0x000000, 0x800000, CRC(dc2806ee) SHA1(587ef391f45bc1de8ad141d8d20958029355ad2c), ROM_BIOS(0)) + + ROM_REGION16_LE(0x80, "eeprom", ROMREGION_ERASEFF) +ROM_END + +#define rom_mako rom_revo + +} // anonymous namespace + -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1999, psion5mx, 0, 0, psion5mx, psion5mx, psion5mx_state, empty_init, "Psion", "Series 5mx", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1999, psion5mx, 0, 0, psion5mx, psion5mx, psion5mx_state, init_s5mx, "Psion", "Series 5mx", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 1999, psion5mx_fr, psion5mx, 0, psion5mx, psion5mx_fr, psion5mx_state, init_s5mx, "Psion", "Series 5mx (French)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 1999, psion5mxp, 0, 0, psion5mxp, psion5mx, psion5mx_state, init_s5mx, "Psion", "Series 5mx PRO", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 1999, psion5mxp_de, psion5mxp, 0, psion5mxp, psion5mx_de, psion5mx_state, init_s5mx, "Psion", "Series 5mx PRO (German)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 1999, revo, 0, 0, revo, revo, psion5mx_state, init_revo, "Psion", "Revo", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 1999, revo_de, revo, 0, revo, psion5mx_de, psion5mx_state, init_revo, "Psion", "Revo (German)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 1999, revo_fr, revo, 0, revo, psion5mx_fr, psion5mx_state, init_revo, "Psion", "Revo (French)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 2000, mako, revo, 0, revoplus, revo_us, psion5mx_state, init_revo, "SONICblue", "Diamond Mako", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 2000, mc218, 0, 0, psion5mx, psion5mx, psion5mx_state, init_mc218, "Ericsson", "MC 218", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 2000, mc218_de, mc218, 0, psion5mx, psion5mx_de, psion5mx_state, init_mc218, "Ericsson", "MC 218 (German)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) +COMP( 2000, mc218_fr, mc218, 0, psion5mx, psion5mx_fr, psion5mx_state, init_mc218, "Ericsson", "MC 218 (French)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/psion/psion5mx.h b/src/mame/psion/psion5mx.h deleted file mode 100644 index 2882d469a2f..00000000000 --- a/src/mame/psion/psion5mx.h +++ /dev/null @@ -1,216 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz, Ash Wolf -/*************************************************************************** - - Psion 5mx (EPOC R5) series and peripherals - - Skeleton driver by Ryan Holtz, ported from work by Ash Wolf - -****************************************************************************/ - -#ifndef MAME_PSION_PSION5MX_H -#define MAME_PSION_PSION5MX_H - -#pragma once - -#include "emu.h" -#include "cpu/arm7/arm7.h" -#include "etna.h" -#include "sound/spkrdev.h" - -#include "screen.h" -#include "emupal.h" -#include "speaker.h" - -class psion5mx_state : public driver_device -{ -public: - psion5mx_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - , m_etna(*this, "etna") - , m_lcd_ram(*this, "lcd_ram") - , m_palette(*this, "palette") - , m_speaker(*this, "speaker") - , m_touchx(*this, "TOUCHX") - , m_touchy(*this, "TOUCHY") - , m_touch(*this, "TOUCH") - , m_kbd_cols(*this, "COL%u", 0U) - { - } - - void psion5mx(machine_config &config); - - DECLARE_INPUT_CHANGED_MEMBER(touch_down); - -protected: - virtual void machine_start() override ATTR_COLD; - virtual void machine_reset() override ATTR_COLD; - - TIMER_CALLBACK_MEMBER(update_timer1); - TIMER_CALLBACK_MEMBER(update_timer2); - TIMER_CALLBACK_MEMBER(update_periodic_irq); - TIMER_CALLBACK_MEMBER(update_rtc); - -private: - void palette_init(palette_device &palette); - - uint32_t periphs_r(offs_t offset, uint32_t mem_mask = ~0); - void periphs_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - - void update_timer(int timer); - void set_timer_ctrl(int timer, uint32_t value); - void check_interrupts(); - - enum - { - REG_MEMCFG1 = 0x0000, - REG_MEMCFG2 = 0x0004, - - REG_DRAMCFG = 0x0100, - - REG_LCDCTL = 0x0200, - REG_LCDST = 0x0204, - REG_LCD_DBAR1 = 0x0210, - REG_LCDT0 = 0x0220, - REG_LCDT1 = 0x0224, - REG_LCDT2 = 0x0228, - - REG_PWRSR = 0x0400, - REG_PWRCNT = 0x0404, - REG_HALT = 0x0408, - REG_STBY = 0x040c, - REG_BLEOI = 0x0410, - REG_MCEOI = 0x0414, - REG_TEOI = 0x0418, - REG_STFCLR = 0x041c, - REG_E2EOI = 0x0420, - - REG_INTSR = 0x0500, - REG_INTRSR = 0x0504, - REG_INTENS = 0x0508, - REG_INTENC = 0x050c, - REG_INTTEST1 = 0x0514, - REG_INTTEST2 = 0x0518, - - REG_PUMPCON = 0x0900, - - REG_CODR = 0x0a00, - REG_CONFG = 0x0a04, - REG_COLFG = 0x0a08, - REG_COEOI = 0x0a0c, - REG_COTEST = 0x0a10, - - REG_SSCR0 = 0x0b00, - REG_SSCR1 = 0x0b04, - REG_SSDR = 0x0b0c, - REG_SSSR = 0x0b14, - - REG_TC1LOAD = 0x0c00, - REG_TC1VAL = 0x0c04, - REG_TC1CTRL = 0x0c08, - REG_TC1EOI = 0x0c0c, - REG_TC2LOAD = 0x0c20, - REG_TC2VAL = 0x0c24, - REG_TC2CTRL = 0x0c28, - REG_TC2EOI = 0x0c2c, - - REG_BZCONT = 0x0c40, - - REG_RTCDRL = 0x0d00, - REG_RTCDRU = 0x0d04, - REG_RTCMRL = 0x0d08, - REG_RTCMRU = 0x0d0c, - REG_RTCEOI = 0x0d10, - - REG_PADR = 0x0e00, - REG_PBDR = 0x0e04, - REG_PCDR = 0x0e08, - REG_PDDR = 0x0e0c, - REG_PADDR = 0x0e10, - REG_PBDDR = 0x0e14, - REG_PCDDR = 0x0e18, - REG_PDDDR = 0x0e1c, - REG_PEDR = 0x0e20, - REG_PEDDR = 0x0e24, - - REG_KSCAN = 0x0e28, - REG_LCDMUX = 0x0e2c - }; - - enum - { - IRQ_EXTFIQ = 0, // FiqExternal - IRQ_BLINT = 1, // FiqBatLow - IRQ_WEINT = 2, // FiqWatchDog - IRQ_MCINT = 3, // FiqMediaChg - IRQ_CSINT = 4, // IrqCodec - IRQ_EINT1 = 5, // IrqExt1 - IRQ_EINT2 = 6, // IrqExt2 - IRQ_EINT3 = 7, // IrqExt3 - IRQ_TC1OI = 8, // IrqTimer1 - IRQ_TC2OI = 9, // IrqTimer2 - IRQ_RTCMI = 10, // IrqRtcMatch - IRQ_TINT = 11, // IrqTick - IRQ_UART1 = 12, // IrqUart1 - IRQ_UART2 = 13, // IrqUart2 - IRQ_LCDINT = 14, // IrqLcd - IRQ_SSEOTI = 15, // IrqSpi - IRQ_FIQ_MASK = 0x000f, - IRQ_IRQ_MASK = 0xfff0 - }; - - enum - { - PORTA, - PORTB, - PORTC, - PORTD, - PORTE - }; - - void main_map(address_map &map) ATTR_COLD; - - uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - - uint8_t read_keyboard(); - - required_device<arm710t_cpu_device> m_maincpu; - required_device<etna_device> m_etna; - required_shared_ptr<uint32_t> m_lcd_ram; - required_device<palette_device> m_palette; - required_device<speaker_sound_device> m_speaker; - required_ioport m_touchx; - required_ioport m_touchy; - required_ioport m_touch; - required_ioport_array<8> m_kbd_cols; - - emu_timer *m_timers[2]{}; - - uint32_t m_memcfg[2]{}; - uint16_t m_dramcfg = 0; - - uint16_t m_timer_reload[2]{}; - uint16_t m_timer_ctrl[2]{}; - uint16_t m_timer_value[2]{}; - - uint32_t m_pending_ints = 0; - uint32_t m_int_mask = 0; - - uint32_t m_lcd_display_base_addr = 0; - - uint32_t m_rtc = 0; - uint32_t m_pwrsr = 0; - uint32_t m_last_ssi_request = 0; - uint32_t m_ssi_read_counter = 0; - uint8_t m_buzzer_ctrl = 0; - - uint8_t m_kbd_scan = 0; - - uint8_t m_ports[5]{}; - - emu_timer *m_periodic = nullptr; - emu_timer *m_rtc_ticker = nullptr; -}; - -#endif // MAME_PSION_PSION5MX_H diff --git a/src/mame/psion/windermere.cpp b/src/mame/psion/windermere.cpp new file mode 100644 index 00000000000..d8692cef732 --- /dev/null +++ b/src/mame/psion/windermere.cpp @@ -0,0 +1,990 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, Nigel Barnes +// thanks-to:Ash Wolf +/*************************************************************************** + + Psion Windermere peripheral emulation + + Windermere is a SoC based around the ARM710T processor core. + + Functionality includes: + - ARM7TDMI CPU core + - Interrupt controller + - CODEC interface + - LCD controller + - 2 x UART's + - Timer counters + - RTC + +***************************************************************************/ + +#include "emu.h" +#include "windermere.h" +#include "screen.h" + + +#define LOG_UNKN (1U << 1) +#define LOG_IRQ (1U << 2) +#define LOG_DRAM (1U << 4) +#define LOG_LCD (1U << 5) +#define LOG_PWR (1U << 6) +#define LOG_EOI (1U << 7) +#define LOG_INT (1U << 8) +#define LOG_CODEC (1U << 9) +#define LOG_SSP (1U << 10) +#define LOG_TIMER (1U << 11) +#define LOG_BUZ (1U << 12) +#define LOG_RTC (1U << 13) +#define LOG_GPIO (1U << 14) +#define LOG_KBD (1U << 15) +#define LOG_UART (1U << 16) + +#define LOG_ALL (LOG_UNKN | LOG_DRAM | LOG_LCD | LOG_PWR | LOG_EOI | LOG_CODEC \ + | LOG_SSP | LOG_TIMER | LOG_BUZ | LOG_RTC | LOG_GPIO | LOG_KBD | LOG_UART) +#define LOG_ALL_IRQ (LOG_IRQ | LOG_EOI | LOG_INT) + +#define VERBOSE (0) +#include "logmacro.h" + + +DEFINE_DEVICE_TYPE(WINDERMERE, windermere_device, "windermere", "Psion Windermere") + +windermere_device::windermere_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, WINDERMERE, tag, owner, clock) + , device_video_interface(mconfig, *this, false) + , m_maincpu(*this, finder_base::DUMMY_TAG) + , m_lcd_dma_cb(*this, 0x00) + , m_buz_cb(*this) + , m_col_cb(*this) + , m_ssp_r(*this, 0) + , m_port_r(*this, 0x00) + , m_port_w(*this) + , m_pcm_in(*this, 0) + , m_pcm_out(*this) +{ +} + + +void windermere_device::device_start() +{ + m_timer[0] = timer_alloc(FUNC(windermere_device::update_timer), this); + m_timer[1] = timer_alloc(FUNC(windermere_device::update_timer), this); + m_rtc_ticker = timer_alloc(FUNC(windermere_device::update_rtc), this); + m_codec_timer = timer_alloc(FUNC(windermere_device::update_codec), this); + + m_buzzer_tog = 0; + + save_item(NAME(m_memcfg)); + save_item(NAME(m_dramcfg)); + + save_item(NAME(m_timer_load)); + save_item(NAME(m_timer_value)); + save_item(NAME(m_timer_ctrl)); + + save_item(NAME(m_pending_ints)); + save_item(NAME(m_int_mask)); + + save_item(NAME(m_uartfcr)); + save_item(NAME(m_uartcon)); + + save_item(NAME(m_lcd_base_addr)); + save_item(NAME(m_lcd_control)); + save_item(NAME(m_lcd_timing)); + + save_item(NAME(m_rtc)); + save_item(NAME(m_pwrsr)); + save_item(NAME(m_pwrcnt)); + save_item(NAME(m_pumpcon)); + save_item(NAME(m_kscan)); + save_item(NAME(m_last_ssi_request)); + save_item(NAME(m_ssi_read_counter)); + save_item(NAME(m_confg)); + + save_item(NAME(m_port_data)); + save_item(NAME(m_port_ddr)); +} + +void windermere_device::device_reset() +{ + m_memcfg[0] = 0; + m_memcfg[1] = 0; + m_dramcfg = 0; + + m_timer_ctrl[0] = m_timer_value[0] = m_timer_load[0] = 0; + m_timer_ctrl[1] = m_timer_value[1] = m_timer_load[1] = 0; + + m_timer[0]->adjust(attotime::never); + m_timer[1]->adjust(attotime::never); + + m_pending_ints = 0; + m_int_mask = 0; + + m_lcd_base_addr[0] = 0; + m_lcd_base_addr[1] = 0; + m_lcd_control = 0; + + m_maincpu->set_unscaled_clock(clock() * 5); + + m_rtc = time(nullptr) - 946684800; + m_pwrsr = (1 << 7) | (1 << 12); // DCDET, PFFLG + m_pwrcnt = 0; + m_kscan = 0; + m_last_ssi_request = 0; + m_ssi_read_counter = 0; + m_confg = 0; + + std::fill(std::begin(m_port_data), std::end(m_port_data), 0); + std::fill(std::begin(m_port_ddr), std::end(m_port_ddr), 0); + + m_rtc_ticker->adjust(attotime::from_hz(64), 0, attotime::from_hz(64)); + m_codec_timer->adjust(attotime::from_hz(8000), 0, attotime::from_hz(8000)); +} + +void windermere_device::extfiq_w(int state) +{ + // level triggered, active low + if (state) + m_pending_ints |= (1 << IRQ_EXTFIQ); + else + m_pending_ints &= ~(1 << IRQ_EXTFIQ); + + check_interrupts(); +} + +void windermere_device::eint1_w(int state) +{ + // level triggered, active low + if (state) + m_pending_ints |= (1 << IRQ_EINT1); + else + m_pending_ints &= ~(1 << IRQ_EINT1); + + check_interrupts(); +} + +void windermere_device::eint2_w(int state) +{ + // edge triggered, active low + if (state) + m_pending_ints |= (1 << IRQ_EINT2); + + check_interrupts(); +} + +void windermere_device::eint3_w(int state) +{ + // level triggered, active high + if (state) + m_pending_ints |= (1 << IRQ_EINT3); + else + m_pending_ints &= ~(1 << IRQ_EINT3); + + check_interrupts(); +} + +void windermere_device::check_interrupts() +{ + LOGMASKED(LOG_IRQ, "Pending FIQs is %04x & %04x & %04x\n", m_pending_ints, m_int_mask, IRQ_FIQ_MASK); + LOGMASKED(LOG_IRQ, "Pending IRQs is %04x & %04x & %04x\n", m_pending_ints, m_int_mask, IRQ_IRQ_MASK); + + if (m_pending_ints & m_int_mask) + { + m_maincpu->resume(SUSPEND_REASON_HALT); + } + + m_maincpu->set_input_line(arm7_cpu_device::ARM7_FIRQ_LINE, m_pending_ints & m_int_mask & IRQ_FIQ_MASK ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(arm7_cpu_device::ARM7_IRQ_LINE, m_pending_ints & m_int_mask & IRQ_IRQ_MASK ? ASSERT_LINE : CLEAR_LINE); +} + + +TIMER_CALLBACK_MEMBER(windermere_device::update_timer) +{ + if (--m_timer_value[param] == 0) + { + if ((param == 0) && BIT(m_buzzer_ctrl, 1)) + { + m_buz_cb(m_buzzer_tog ^= 1); + } + + LOGMASKED(LOG_IRQ, "Flagging Timer %d IRQ\n", param + 1); + m_pending_ints |= (1 << (IRQ_TC1OI + param)); + check_interrupts(); + + if (BIT(m_timer_ctrl[param], 6)) + { + m_timer_value[param] = m_timer_load[param]; + } + } +} + +TIMER_CALLBACK_MEMBER(windermere_device::update_rtc) +{ + LOGMASKED(LOG_IRQ, "Flagging periodic IRQ\n"); + if (m_pending_ints & (1 << IRQ_TINT)) + m_pending_ints |= 1 << IRQ_WEINT; + else + m_pending_ints |= 1 << IRQ_TINT; + + if ((m_pwrsr & 0x3f) == 0x3f) + { + m_rtc++; + m_pwrsr &= ~0x3f; + } + else + { + m_pwrsr++; + } + + check_interrupts(); +} + +TIMER_CALLBACK_MEMBER(windermere_device::update_codec) +{ + if (BIT(m_confg, 0)) // Enable CODEC data output + { + if (!m_codec_tx.empty()) + m_pcm_out(m_codec_tx.dequeue()); + + if (m_codec_tx.queue_length() == 8) + { + m_pending_ints |= 1 << IRQ_CSINT; + check_interrupts(); + } + } + + if (BIT(m_confg, 1)) // Enable CODEC data input + { + if (!m_codec_rx.full()) + m_codec_rx.enqueue(m_pcm_in()); + + if (m_codec_rx.queue_length() == 8) + { + m_pending_ints |= 1 << IRQ_CSINT; + check_interrupts(); + } + } +} + + +void windermere_device::set_timer_ctrl(int timer, uint8_t data) +{ + const uint16_t old = m_timer_ctrl[timer]; + const uint16_t changed = old ^ data; + + m_timer_ctrl[timer] = data; + + if (changed != 0) + { + attotime interval = BIT(m_timer_ctrl[timer], 3) ? attotime::from_ticks(1, 512000) : attotime::from_ticks(1, 2000); + if (BIT(old, 7) && BIT(data, 7)) + { + m_timer[timer]->adjust(m_timer[timer]->remaining(), timer, interval); + } + else if (BIT(data, 7)) + { + m_timer[timer]->adjust(interval, timer, interval); + } + else + { + m_timer[timer]->adjust(attotime::never); + } + } +} + + +uint32_t windermere_device::periphs_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0xffffffff; + + switch (offset << 2) + { + case REG_MEMCFG1: + data = m_memcfg[0]; + LOGMASKED(LOG_DRAM, "%s: peripheral read MEMCFG1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_MEMCFG2: + data = m_memcfg[1]; + LOGMASKED(LOG_DRAM, "%s: peripheral read MEMCFG2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_DRAMCFG: + data = m_dramcfg; + LOGMASKED(LOG_DRAM, "%s: peripheral read DRAMCFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_LCDCTL: + data = m_lcd_control; + LOGMASKED(LOG_LCD, "%s: peripheral read LCDCTL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCDST: + data = 0; + LOGMASKED(LOG_LCD, "%s: peripheral read LCDST = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCD_DBAR1: + data = m_lcd_base_addr[0]; + LOGMASKED(LOG_LCD, "%s: peripheral read DBAR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCD_DBAR2: + data = m_lcd_base_addr[1]; + LOGMASKED(LOG_LCD, "%s: peripheral read DBAR2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCDT0: + data = m_lcd_timing[0]; + LOGMASKED(LOG_LCD, "%s: peripheral read LCDT0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCDT1: + data = m_lcd_timing[1]; + LOGMASKED(LOG_LCD, "%s: peripheral read LCDT1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCDT2: + data = m_lcd_timing[2]; + LOGMASKED(LOG_LCD, "%s: peripheral read LCDT2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_PWRSR: + data = m_pwrsr; + LOGMASKED(LOG_PWR, "%s: peripheral read PWRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PWRCNT: + data = m_pwrcnt; + LOGMASKED(LOG_PWR, "%s: peripheral read PWRCNT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_INTSR: + data = m_pending_ints & m_int_mask; + LOGMASKED(LOG_INT, "%s: peripheral read INTSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_INTRSR: + data = m_pending_ints; + LOGMASKED(LOG_INT, "%s: peripheral read INTRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_INTENS: + data = m_int_mask; + LOGMASKED(LOG_INT, "%s: peripheral read INTENS = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_INTTEST1: + LOGMASKED(LOG_INT, "%s: peripheral read INTTEST1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_INTTEST2: + LOGMASKED(LOG_INT, "%s: peripheral read INTTEST2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_UART1DR: + LOGMASKED(LOG_UART, "%s: peripheral read UART1DR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1FCR: + data = m_uartfcr[0]; + LOGMASKED(LOG_UART, "%s: peripheral read UART1FCR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1BR: + LOGMASKED(LOG_UART, "%s: peripheral read UART1BR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1CON: + data = m_uartcon[0]; + LOGMASKED(LOG_UART, "%s: peripheral read UART1CON = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1FLG: + data = 0x10; + LOGMASKED(LOG_UART, "%s: peripheral read UART1FLG = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1INT: + LOGMASKED(LOG_UART, "%s: peripheral read UART1INT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1INTM: + LOGMASKED(LOG_UART, "%s: peripheral read UART1INTM = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1INTR: + LOGMASKED(LOG_UART, "%s: peripheral read UART1INTR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_UART2DR: + LOGMASKED(LOG_UART, "%s: peripheral read UART2DR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2FCR: + data = m_uartfcr[1]; + LOGMASKED(LOG_UART, "%s: peripheral read UART2FCR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2BR: + LOGMASKED(LOG_UART, "%s: peripheral read UART2BR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2CON: + data = m_uartcon[1]; + LOGMASKED(LOG_UART, "%s: peripheral read UART2CON = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2FLG: + data = 0x10; + LOGMASKED(LOG_UART, "%s: peripheral read UART2FLG = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2INT: + LOGMASKED(LOG_UART, "%s: peripheral read UART2INT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2INTM: + LOGMASKED(LOG_UART, "%s: peripheral read UART2INTM = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2INTR: + LOGMASKED(LOG_UART, "%s: peripheral read UART2INTR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_PUMPCON: + data = m_pumpcon; + LOGMASKED(LOG_PWR, "%s: peripheral read PUMPCON = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_CODR: + data = m_codec_rx.dequeue(); + LOGMASKED(LOG_CODEC, "%s: peripheral read CODR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_CONFG: + data = m_confg; + LOGMASKED(LOG_CODEC, "%s: peripheral read CONFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_COLFG: + data = (m_codec_tx.full() ? 0x02 : 0x00) | (m_codec_rx.empty() ? 0x01 : 0x00); + LOGMASKED(LOG_CODEC, "%s: peripheral read COLFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_COTEST: + LOGMASKED(LOG_CODEC, "%s: peripheral read COTEST = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_SSCR0: + data = 0; + LOGMASKED(LOG_SSP, "%s: peripheral read SSCR0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_SSCR1: + data = 0; + LOGMASKED(LOG_SSP, "%s: peripheral read SSCR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_SSDR: + { + // TODO: Proper SSP support + uint16_t value = m_ssp_r(m_last_ssi_request); + data = 0; + switch (m_ssi_read_counter) + { + case 4: data = (value >> 5) & 0x7f; break; + case 5: data = (value << 3) & 0xf8; break; + } + if (++m_ssi_read_counter == 6) m_ssi_read_counter = 0; + + // We should be clearing SSEOTI here, possibly, + // but for now we just leave it on to simplify things + LOGMASKED(LOG_SSP, "%s: peripheral read SSDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + } + case REG_SSSR: + data = 0; + LOGMASKED(LOG_SSP, "%s: peripheral read SSSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_TC1LOAD: + data = m_timer_load[0]; + LOGMASKED(LOG_TIMER, "%s: peripheral read TC1LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_TC1VAL: + data = m_timer_value[0]; + LOGMASKED(LOG_TIMER, "%s: peripheral read TC1VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_TC1CTRL: + data = m_timer_ctrl[0]; + LOGMASKED(LOG_TIMER, "%s: peripheral read TC1CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_TC2LOAD: + data = m_timer_load[1]; + LOGMASKED(LOG_TIMER, "%s: peripheral read TC2LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_TC2VAL: + data = m_timer_value[1]; + LOGMASKED(LOG_TIMER, "%s: peripheral read TC2VAL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_TC2CTRL: + data = m_timer_ctrl[1]; + LOGMASKED(LOG_TIMER, "%s: peripheral read TC2CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_RTCDRL: + data = m_rtc & 0xffff; + LOGMASKED(LOG_RTC, "%s: peripheral read RTCDRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_RTCDRU: + data = m_rtc >> 16; + LOGMASKED(LOG_RTC, "%s: peripheral read RTCDRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_RTCMRL: + LOGMASKED(LOG_RTC, "%s: peripheral read RTCMRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_RTCMRU: + LOGMASKED(LOG_RTC, "%s: peripheral read RTCMRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_PADR: + data = (m_port_data[PORTA] & m_port_ddr[PORTA]) | (m_port_r[PORTA]() & ~m_port_ddr[PORTA]); + LOGMASKED(LOG_GPIO, "%s: peripheral read PADR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PBDR: + data = (m_port_data[PORTB] & m_port_ddr[PORTB]) | (m_port_r[PORTB]() & ~m_port_ddr[PORTB]); + LOGMASKED(LOG_GPIO, "%s: peripheral read PBDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PCDR: + data = (m_port_data[PORTC] & ~m_port_ddr[PORTC]) | (m_port_r[PORTC]() & m_port_ddr[PORTC]); + LOGMASKED(LOG_GPIO, "%s: peripheral read PCDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PDDR: + data = (m_port_data[PORTD] & ~m_port_ddr[PORTD]) | (m_port_r[PORTD]() & m_port_ddr[PORTD]); + LOGMASKED(LOG_GPIO, "%s: peripheral read PDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PADDR: + data = m_port_ddr[PORTA]; + LOGMASKED(LOG_GPIO, "%s: peripheral read PADDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PBDDR: + data = m_port_ddr[PORTB]; + LOGMASKED(LOG_GPIO, "%s: peripheral read PBDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PCDDR: + data = m_port_ddr[PORTC]; + LOGMASKED(LOG_GPIO, "%s: peripheral read PCDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PDDDR: + data = m_port_ddr[PORTD]; + LOGMASKED(LOG_GPIO, "%s: peripheral read PDDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PEDR: + data = (m_port_data[PORTE] & m_port_ddr[PORTE]) | (m_port_r[PORTE]() & ~m_port_ddr[PORTE]); + LOGMASKED(LOG_GPIO, "%s: peripheral read PEDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_PEDDR: + data = m_port_ddr[PORTE]; + LOGMASKED(LOG_GPIO, "%s: peripheral read PEDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_KSCAN: + data = m_kscan; + LOGMASKED(LOG_KBD, "%s: peripheral read KSCAN = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCDMUX: + LOGMASKED(LOG_LCD, "%s: peripheral read LCDMUX = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + default: + LOGMASKED(LOG_UNKN, "%s: peripheral read Unknown %04x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask); + break; + } + return data; +} + +void windermere_device::periphs_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + switch (offset << 2) + { + case REG_MEMCFG1: + m_memcfg[0] = data; + LOGMASKED(LOG_DRAM, "%s: peripheral write MEMCFG1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_MEMCFG2: + m_memcfg[1] = data; + LOGMASKED(LOG_DRAM, "%s: peripheral write MEMCFG2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_DRAMCFG: + m_dramcfg = data; + LOGMASKED(LOG_DRAM, "%s: peripheral write DRAMCFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_LCDCTL: + LOGMASKED(LOG_LCD, "%s: peripheral write LCDCTL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_lcd_control = data; + break; + case REG_LCDST: + LOGMASKED(LOG_LCD, "%s: peripheral write LCDST = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_LCD_DBAR1: + LOGMASKED(LOG_LCD, "%s: peripheral write DBAR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_lcd_base_addr[0]); + break; + case REG_LCD_DBAR2: + LOGMASKED(LOG_LCD, "%s: peripheral write DBAR2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_lcd_base_addr[1]); + break; + case REG_LCDT0: + LOGMASKED(LOG_LCD, "%s: peripheral write LCDT0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_lcd_timing[0] = data; + break; + case REG_LCDT1: + LOGMASKED(LOG_LCD, "%s: peripheral write LCDT1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_lcd_timing[1] = data; + break; + case REG_LCDT2: + LOGMASKED(LOG_LCD, "%s: peripheral write LCDT2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_lcd_timing[2] = data; + break; + + case REG_PWRSR: + LOGMASKED(LOG_PWR, "%s: peripheral write PWRSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_pwrsr); + break; + case REG_PWRCNT: + LOGMASKED(LOG_PWR, "%s: peripheral write PWRCNT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pwrcnt = data; + m_maincpu->set_unscaled_clock(clock() * (BIT(data, 2) ? 10 : 5)); + break; + case REG_HALT: + LOGMASKED(LOG_PWR, "%s: peripheral write HALT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_maincpu->suspend(SUSPEND_REASON_HALT, true); + m_pwrsr &= ~0x0200; + break; + case REG_STBY: + LOGMASKED(LOG_PWR, "%s: peripheral write STBY = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pwrsr &= ~0x0200; + break; + case REG_BLEOI: + LOGMASKED(LOG_EOI, "%s: peripheral write BLEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_BLINT); + check_interrupts(); + break; + case REG_MCEOI: + LOGMASKED(LOG_EOI, "%s: peripheral write MCEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_MCINT); + check_interrupts(); + break; + case REG_TEOI: + LOGMASKED(LOG_EOI, "%s: peripheral write TEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_TINT); + m_pending_ints &= ~(1 << IRQ_WEINT); + check_interrupts(); + break; + case REG_STFCLR: + LOGMASKED(LOG_PWR, "%s: peripheral write STFCLR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pwrsr &= ~0x3e00; + break; + case REG_E2EOI: + LOGMASKED(LOG_EOI, "%s: peripheral write E2EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_EINT2); + check_interrupts(); + break; + + case REG_INTENS: + LOGMASKED(LOG_INT, "%s: peripheral write INTENS = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_int_mask |= data & mem_mask; + check_interrupts(); + break; + case REG_INTENC: + LOGMASKED(LOG_INT, "%s: peripheral write INTENC = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_int_mask &= ~(data & mem_mask); + check_interrupts(); + break; + case REG_INTTEST1: + LOGMASKED(LOG_INT, "%s: peripheral write INTTEST1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_INTTEST2: + LOGMASKED(LOG_INT, "%s: peripheral write INTTEST2 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_UART1DR: + LOGMASKED(LOG_UART, "%s: peripheral write UART1DR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1FCR: + LOGMASKED(LOG_UART, "%s: peripheral write UART1FCR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_uartfcr[0] = data; + break; + case REG_UART1BR: + LOGMASKED(LOG_UART, "%s: peripheral write UART1BR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART1CON: + LOGMASKED(LOG_UART, "%s: peripheral write UART1CON = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_uartcon[0] = data; + break; + case REG_UART1INTM: + LOGMASKED(LOG_UART, "%s: peripheral write UART1INTM = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_UART2DR: + LOGMASKED(LOG_UART, "%s: peripheral write UART2DR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2FCR: + LOGMASKED(LOG_UART, "%s: peripheral write UART2FCR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_uartfcr[1] = data; + break; + case REG_UART2BR: + LOGMASKED(LOG_UART, "%s: peripheral write UART2BR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2CON: + LOGMASKED(LOG_UART, "%s: peripheral write UART2CON = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_uartcon[1] = data; + break; + case REG_UART2INT: + LOGMASKED(LOG_UART, "%s: peripheral write UART2INT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_UART2INTM: + LOGMASKED(LOG_UART, "%s: peripheral write UART2INTM = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_PUMPCON: + LOGMASKED(LOG_PWR, "%s: peripheral write PUMPCON = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pumpcon = data; + break; + + case REG_CODR: + LOGMASKED(LOG_CODEC, "%s: peripheral write CODR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_codec_tx.enqueue(data & 0xff); + break; + case REG_CONFG: + LOGMASKED(LOG_CODEC, "%s: peripheral write CONFG = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_confg = data; + break; + case REG_COEOI: + LOGMASKED(LOG_CODEC | LOG_EOI, "%s: peripheral write COEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_CSINT); + check_interrupts(); + break; + + case REG_SSCR0: + LOGMASKED(LOG_SSP, "%s: peripheral write SSCR0 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_SSCR1: + LOGMASKED(LOG_SSP, "%s: peripheral write SSCR1 = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_SSDR: + LOGMASKED(LOG_SSP, "%s: peripheral write SSDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + // TODO: Proper SPI support + if (data != 0) + { + m_last_ssi_request = (m_last_ssi_request >> 8) | (data & 0xff00); + } + break; + case REG_SSSR: + LOGMASKED(LOG_SSP, "%s: peripheral write SSSR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + case REG_TC1LOAD: + LOGMASKED(LOG_TIMER, "%s: peripheral write TC1LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_timer_load[0] = data; + m_timer_value[0] = data; + break; + case REG_TC1CTRL: + LOGMASKED(LOG_TIMER, "%s: peripheral write TC1CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + set_timer_ctrl(0, data); + break; + case REG_TC1EOI: + LOGMASKED(LOG_TIMER | LOG_EOI, "%s: peripheral write TC1EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_TC1OI); + check_interrupts(); + break; + case REG_TC2LOAD: + LOGMASKED(LOG_TIMER, "%s: peripheral write TC2LOAD = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_timer_load[1] = data; + m_timer_value[1] = data; + break; + case REG_TC2CTRL: + LOGMASKED(LOG_TIMER, "%s: peripheral write TC2CTRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + set_timer_ctrl(1, data); + break; + case REG_TC2EOI: + LOGMASKED(LOG_TIMER | LOG_EOI, "%s: peripheral write TC2EOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_TC2OI); + check_interrupts(); + break; + + case REG_BZCONT: + LOGMASKED(LOG_BUZ, "%s: peripheral write BZCONT = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_buzzer_ctrl = data; + if (!BIT(m_buzzer_ctrl, 1)) + { + m_buz_cb(BIT(m_buzzer_ctrl, 0)); + } + break; + + case REG_RTCDRL: + LOGMASKED(LOG_RTC, "%s: peripheral write RTCDRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_rtc &= 0xffff0000; + m_rtc |= (data & 0xffff); + break; + case REG_RTCDRU: + LOGMASKED(LOG_RTC, "%s: peripheral write RTCDRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_rtc &= 0x0000ffff; + m_rtc |= (data & 0xffff) << 16; + break; + case REG_RTCMRL: + LOGMASKED(LOG_RTC, "%s: peripheral write RTCMRL = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_RTCMRU: + LOGMASKED(LOG_RTC, "%s: peripheral write RTCMRU = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + case REG_RTCEOI: + LOGMASKED(LOG_RTC | LOG_EOI, "%s: peripheral write RTCEOI = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_pending_ints &= ~(1 << IRQ_RTCMI); + check_interrupts(); + break; + + case REG_PADR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PADR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + if (data != m_port_data[PORTA]) + { + m_port_data[PORTA] = data; + m_port_w[PORTA](PORTA, data | ~m_port_ddr[PORTA], m_port_ddr[PORTA]); + } + break; + case REG_PBDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PBDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + if (data != m_port_data[PORTB]) + { + m_port_data[PORTB] = data; + m_port_w[PORTB](PORTB, data | ~m_port_ddr[PORTB], m_port_ddr[PORTB]); + } + //const uint8_t old = m_port_data[PORTB]; + //const uint8_t diff = old ^ data; + //if (diff & 0x3c) + // LOGMASKED(LOG_PIN, "Contrast: %d\n", (data >> 2) & 0x0f); + //if (BIT(diff, 6)) + // LOGMASKED(LOG_PIN, "Case Open: %d\n", BIT(data, 6)); + //if (BIT(diff, 7)) + // LOGMASKED(LOG_PIN, "ETNA CompactFlash Power: %d\n", BIT(data, 7)); + break; + case REG_PCDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PCDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + if (data != m_port_data[PORTC]) + { + m_port_data[PORTC] = data; + m_port_w[PORTC](PORTC, data | m_port_ddr[PORTC], ~m_port_ddr[PORTC]); + } + //const uint8_t old = m_port_data[PORTC]; + //const uint8_t diff = old ^ data; + //if (BIT(diff, 0)) + // LOGMASKED(LOG_PIN, "RS232 RTS: %d\n", BIT(data, 0)); + //if (BIT(diff, 1)) + // LOGMASKED(LOG_PIN, "RS232 DTR Toggle: %d\n", BIT(data, 1)); + //if (BIT(diff, 2)) + // LOGMASKED(LOG_PIN, "Disable Power LED: %d\n", BIT(data, 2)); + //if (BIT(diff, 3)) + // LOGMASKED(LOG_PIN, "Enable UART1: %d\n", BIT(data, 3)); + //if (BIT(diff, 4)) + // LOGMASKED(LOG_PIN, "LCD Backlight: %d\n", BIT(data, 4)); + //if (BIT(diff, 5)) + // LOGMASKED(LOG_PIN, "Enable UART0: %d\n", BIT(data, 5)); + //if (BIT(diff, 6)) + // LOGMASKED(LOG_PIN, "Dictaphone: %d\n", BIT(data, 6)); + break; + case REG_PDDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + if (data != m_port_data[PORTD]) + { + m_port_data[PORTD] = data; + m_port_w[PORTD](PORTD, data | m_port_ddr[PORTD], ~m_port_ddr[PORTD]); + } + //const uint8_t old = m_port_data[PORTD]; + //const uint8_t diff = old ^ data; + //if (BIT(diff, 0)) + // LOGMASKED(LOG_PIN, "Codec Enable: %d\n", BIT(data, 0)); + //if (BIT(diff, 1)) + // LOGMASKED(LOG_PIN, "Audio Amp Enable: %d\n", BIT(data, 1)); + //if (BIT(diff, 2)) + // LOGMASKED(LOG_PIN, "LCD Power: %d\n", BIT(data, 2)); + //if (BIT(diff, 3)) + // LOGMASKED(LOG_PIN, "ETNA Door: %d\n", BIT(data, 3)); + //if (BIT(diff, 4)) + // LOGMASKED(LOG_PIN, "Sled: %d\n", BIT(data, 4)); + //if (BIT(diff, 5)) + // LOGMASKED(LOG_PIN, "Pump Power2: %d\n", BIT(data, 5)); + //if (BIT(diff, 6)) + // LOGMASKED(LOG_PIN, "Pump Power1: %d\n", BIT(data, 6)); + //if (BIT(diff, 7)) + // LOGMASKED(LOG_PIN, "ETNA Error: %d\n", BIT(data, 7)); + break; + case REG_PADDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PADDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_port_ddr[PORTA] = data; + break; + case REG_PBDDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PBDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_port_ddr[PORTB] = data; + break; + case REG_PCDDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PCDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_port_ddr[PORTC] = data; + break; + case REG_PDDDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PDDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_port_ddr[PORTD] = data; + break; + case REG_PEDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PEDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + if (data != m_port_data[PORTE]) + { + m_port_data[PORTE] = data; + m_port_w[PORTE](PORTE, data | ~m_port_ddr[PORTE], m_port_ddr[PORTE]); + } + break; + case REG_PEDDR: + LOGMASKED(LOG_GPIO, "%s: peripheral write PEDDR = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_port_ddr[PORTE] = data; + break; + + case REG_KSCAN: + LOGMASKED(LOG_KBD, "%s: peripheral write KSCAN = %08x & %08x\n", machine().describe_context(), data, mem_mask); + m_kscan = data; + if (BIT(data, 3)) + m_col_cb(1 << (data & 7)); + else if (data & 0x0f) + m_col_cb(0x00); + else + m_col_cb(0xff); + break; + case REG_LCDMUX: + LOGMASKED(LOG_LCD, "%s: peripheral write LCDMUX = %08x & %08x\n", machine().describe_context(), data, mem_mask); + break; + + default: + LOGMASKED(LOG_UNKN, "%s: peripheral write Unknown %04x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask); + break; + } +} + + +//------------------------------------------------- +// LCD Controller +//------------------------------------------------- + +uint32_t windermere_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + if (BIT(m_lcd_control, 0)) // LCD Enable + { + const uint32_t base_addr = m_lcd_base_addr[0] & 0x3ffffff; + + const int width = (m_lcd_timing[0] & 0x3f0) + 16; + const int height = (m_lcd_timing[1] & 0x3ff) + 1; + + const int bpp = 1 << (m_lcd_dma_cb(base_addr + 1) >> 4); + const int ppb = 8 / bpp; + + LOGMASKED(LOG_LCD, "bpp: %d, ppb: %d\n", bpp, ppb); + uint16_t palette[16] = {}; + for (int i = 0; i < 16; i++) + { + palette[i] = m_lcd_dma_cb(base_addr + (i * 2)) | ((m_lcd_dma_cb(base_addr + (i * 2) + 1) << 8) & 0xf00); + LOGMASKED(LOG_LCD, "palette[%d]: %04x\n", i, palette[i]); + } + + const pen_t *pen = screen.palette().pens(); + + // build our image out + const int line_width = (width * bpp) / 8; + for (int y = 0; y < height; y++) + { + const int line_offs = 0x20 + (line_width * y); + uint16_t *line = &bitmap.pix(y + m_lcd_y_offset); + for (int x = 0; x < width; x++) + { + const uint8_t byte = m_lcd_dma_cb(base_addr + line_offs + (x / ppb)); + const int shift = (x & (ppb - 1)) * bpp; + const int mask = (1 << bpp) - 1; + const int pal_idx = (byte >> shift) & mask; + + line[x + m_lcd_x_offset] = pen[palette[pal_idx]]; + } + } + } + else + { + bitmap.fill(0, cliprect); + } + return 0; +} diff --git a/src/mame/psion/windermere.h b/src/mame/psion/windermere.h new file mode 100644 index 00000000000..8f68824c591 --- /dev/null +++ b/src/mame/psion/windermere.h @@ -0,0 +1,263 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz, Nigel Barnes +// thanks-to:Ash Wolf +/*************************************************************************** + + Psion Windermere peripheral emulation + +***************************************************************************/ + +#ifndef MAME_PSION_WINDERMERE_H +#define MAME_PSION_WINDERMERE_H + +#pragma once + +#include "cpu/arm7/arm7.h" + + +class windermere_device : public device_t, + public device_video_interface +{ +public: + windermere_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template <typename T> + windermere_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cpu_tag) + : windermere_device(mconfig, tag, owner, clock) + { + m_maincpu.set_tag(std::forward<T>(cpu_tag)); + } + + void set_screen_origin(uint16_t x_offset, uint16_t y_offset) { m_lcd_x_offset = x_offset; m_lcd_y_offset = y_offset; } + + // callbacks + auto lcd_dma_cb() { return m_lcd_dma_cb.bind(); } + auto buz_cb() { return m_buz_cb.bind(); } + auto col_cb() { return m_col_cb.bind(); } + auto ssp_r() { return m_ssp_r.bind(); } + + auto pcm_in() { return m_pcm_in.bind(); } + auto pcm_out() { return m_pcm_out.bind(); } + + auto porta_r() { return m_port_r[PORTA].bind(); } + auto porta_w() { return m_port_w[PORTA].bind(); } + auto portb_r() { return m_port_r[PORTB].bind(); } + auto portb_w() { return m_port_w[PORTB].bind(); } + auto portc_r() { return m_port_r[PORTC].bind(); } + auto portc_w() { return m_port_w[PORTC].bind(); } + auto portd_r() { return m_port_r[PORTD].bind(); } + auto portd_w() { return m_port_w[PORTD].bind(); } + auto porte_r() { return m_port_r[PORTE].bind(); } + auto porte_w() { return m_port_w[PORTE].bind(); } + + void extfiq_w(int state); + void eint1_w(int state); + void eint2_w(int state); + void eint3_w(int state); + + uint32_t periphs_r(offs_t offset, uint32_t mem_mask = ~0); + void periphs_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); + + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + +protected: + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + +private: + TIMER_CALLBACK_MEMBER(update_timer); + TIMER_CALLBACK_MEMBER(update_rtc); + TIMER_CALLBACK_MEMBER(update_codec); + + void set_timer_ctrl(int timer, uint8_t value); + void check_interrupts(); + + // Static Memory Interface + static constexpr uint16_t REG_MEMCFG1 = 0x0000; + static constexpr uint16_t REG_MEMCFG2 = 0x0004; + + // Dynamic Memory Interface + static constexpr uint16_t REG_DRAMCFG = 0x0100; + + // LCD Internal Registers + static constexpr uint16_t REG_LCDCTL = 0x0200; + static constexpr uint16_t REG_LCDST = 0x0204; + static constexpr uint16_t REG_LCD_DBAR1 = 0x0210; + static constexpr uint16_t REG_LCD_DBAR2 = 0x0218; + static constexpr uint16_t REG_LCDT0 = 0x0220; + static constexpr uint16_t REG_LCDT1 = 0x0224; + static constexpr uint16_t REG_LCDT2 = 0x0228; + + // Power/State Control + static constexpr uint16_t REG_PWRSR = 0x0400; + static constexpr uint16_t REG_PWRCNT = 0x0404; + static constexpr uint16_t REG_HALT = 0x0408; + static constexpr uint16_t REG_STBY = 0x040c; + static constexpr uint16_t REG_BLEOI = 0x0410; + static constexpr uint16_t REG_MCEOI = 0x0414; + static constexpr uint16_t REG_TEOI = 0x0418; + static constexpr uint16_t REG_STFCLR = 0x041c; + static constexpr uint16_t REG_E2EOI = 0x0420; + + // Interrupt Controller + static constexpr uint16_t REG_INTSR = 0x0500; + static constexpr uint16_t REG_INTRSR = 0x0504; + static constexpr uint16_t REG_INTENS = 0x0508; + static constexpr uint16_t REG_INTENC = 0x050c; + static constexpr uint16_t REG_INTTEST1 = 0x0514; + static constexpr uint16_t REG_INTTEST2 = 0x0518; + + // UART1 and SIR + static constexpr uint16_t REG_UART1DR = 0x0600; + static constexpr uint16_t REG_UART1FCR = 0x0604; + static constexpr uint16_t REG_UART1BR = 0x0608; + static constexpr uint16_t REG_UART1CON = 0x060c; + static constexpr uint16_t REG_UART1FLG = 0x0610; + static constexpr uint16_t REG_UART1INT = 0x0614; + static constexpr uint16_t REG_UART1INTM = 0x0618; + static constexpr uint16_t REG_UART1INTR = 0x061c; + + // UART2 + static constexpr uint16_t REG_UART2DR = 0x0700; + static constexpr uint16_t REG_UART2FCR = 0x0704; + static constexpr uint16_t REG_UART2BR = 0x0708; + static constexpr uint16_t REG_UART2CON = 0x070c; + static constexpr uint16_t REG_UART2FLG = 0x0710; + static constexpr uint16_t REG_UART2INT = 0x0714; + static constexpr uint16_t REG_UART2INTM = 0x0718; + static constexpr uint16_t REG_UART2INTR = 0x071c; + + // DC-DC Converter + static constexpr uint16_t REG_PUMPCON = 0x0900; + + // Codec Interface + static constexpr uint16_t REG_CODR = 0x0a00; + static constexpr uint16_t REG_CONFG = 0x0a04; + static constexpr uint16_t REG_COLFG = 0x0a08; + static constexpr uint16_t REG_COEOI = 0x0a0c; + static constexpr uint16_t REG_COTEST = 0x0a10; + + // Synchronous Serial Interface Port + static constexpr uint16_t REG_SSCR0 = 0x0b00; + static constexpr uint16_t REG_SSCR1 = 0x0b04; + static constexpr uint16_t REG_SSDR = 0x0b0c; + static constexpr uint16_t REG_SSSR = 0x0b14; + + // Counter Timer 1 & 2 + static constexpr uint16_t REG_TC1LOAD = 0x0c00; + static constexpr uint16_t REG_TC1VAL = 0x0c04; + static constexpr uint16_t REG_TC1CTRL = 0x0c08; + static constexpr uint16_t REG_TC1EOI = 0x0c0c; + static constexpr uint16_t REG_TC2LOAD = 0x0c20; + static constexpr uint16_t REG_TC2VAL = 0x0c24; + static constexpr uint16_t REG_TC2CTRL = 0x0c28; + static constexpr uint16_t REG_TC2EOI = 0x0c2c; + static constexpr uint16_t REG_BZCONT = 0x0c40; + + // Real Time Clock + static constexpr uint16_t REG_RTCDRL = 0x0d00; + static constexpr uint16_t REG_RTCDRU = 0x0d04; + static constexpr uint16_t REG_RTCMRL = 0x0d08; + static constexpr uint16_t REG_RTCMRU = 0x0d0c; + static constexpr uint16_t REG_RTCEOI = 0x0d10; + + // Programmable I/O, Keyboard Scan + static constexpr uint16_t REG_PADR = 0x0e00; + static constexpr uint16_t REG_PBDR = 0x0e04; + static constexpr uint16_t REG_PCDR = 0x0e08; + static constexpr uint16_t REG_PDDR = 0x0e0c; + static constexpr uint16_t REG_PADDR = 0x0e10; + static constexpr uint16_t REG_PBDDR = 0x0e14; + static constexpr uint16_t REG_PCDDR = 0x0e18; + static constexpr uint16_t REG_PDDDR = 0x0e1c; + static constexpr uint16_t REG_PEDR = 0x0e20; + static constexpr uint16_t REG_PEDDR = 0x0e24; + static constexpr uint16_t REG_KSCAN = 0x0e28; + static constexpr uint16_t REG_LCDMUX = 0x0e2c; + + static constexpr int IRQ_EXTFIQ = 0; // FiqExternal + static constexpr int IRQ_BLINT = 1; // FiqBatLow + static constexpr int IRQ_WEINT = 2; // FiqWatchDog + static constexpr int IRQ_MCINT = 3; // FiqMediaChg + static constexpr int IRQ_CSINT = 4; // IrqCodec + static constexpr int IRQ_EINT1 = 5; // IrqExt1 + static constexpr int IRQ_EINT2 = 6; // IrqExt2 + static constexpr int IRQ_EINT3 = 7; // IrqExt3 + static constexpr int IRQ_TC1OI = 8; // IrqTimer1 + static constexpr int IRQ_TC2OI = 9; // IrqTimer2 + static constexpr int IRQ_RTCMI = 10; // IrqRtcMatch + static constexpr int IRQ_TINT = 11; // IrqTick + static constexpr int IRQ_UART1 = 12; // IrqUart1 + static constexpr int IRQ_UART2 = 13; // IrqUart2 + static constexpr int IRQ_LCDINT = 14; // IrqLcd + static constexpr int IRQ_SSEOTI = 15; // IrqSpi + + static constexpr uint16_t IRQ_FIQ_MASK = 0x000f; + static constexpr uint16_t IRQ_IRQ_MASK = 0xfff0; + + enum + { + PORTA, + PORTB, + PORTC, + PORTD, + PORTE + }; + + required_device<arm7_cpu_device> m_maincpu; + + devcb_read8 m_lcd_dma_cb; + devcb_write_line m_buz_cb; + devcb_write8 m_col_cb; + devcb_read16 m_ssp_r; + + devcb_read8::array<5> m_port_r; + devcb_write8::array<5> m_port_w; + + devcb_read8 m_pcm_in; + devcb_write8 m_pcm_out; + + emu_timer *m_timer[2]; + + uint32_t m_memcfg[2]; + uint16_t m_dramcfg; + + uint32_t m_lcd_base_addr[2]; + uint32_t m_lcd_control; + uint32_t m_lcd_timing[3]{}; + uint16_t m_lcd_x_offset = 0; + uint16_t m_lcd_y_offset = 0; + + uint16_t m_timer_load[2]; + uint16_t m_timer_ctrl[2]; + uint16_t m_timer_value[2]; + + uint16_t m_pending_ints; + uint16_t m_int_mask; + + uint8_t m_uartfcr[2]{}; + uint8_t m_uartcon[2]{}; + + uint32_t m_rtc; + uint16_t m_pwrsr; + uint16_t m_pwrcnt; + uint16_t m_pumpcon; + uint8_t m_kscan; + uint16_t m_last_ssi_request; + uint16_t m_ssi_read_counter; + uint8_t m_buzzer_ctrl; + int m_buzzer_tog; + uint8_t m_confg; + util::fifo<uint8_t, 16> m_codec_rx; + util::fifo<uint8_t, 16> m_codec_tx; + + uint8_t m_port_data[5]; + uint8_t m_port_ddr[5]; + + emu_timer *m_rtc_ticker; + emu_timer *m_codec_timer; +}; + +DECLARE_DEVICE_TYPE(WINDERMERE, windermere_device) + +#endif // MAME_PSION_WINDERMERE_H |
