summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Nigel Barnes <ngbarnes@gmail.com>2026-05-16 15:40:39 +0100
committer Nigel Barnes <ngbarnes@gmail.com>2026-05-16 16:15:25 +0100
commita7e361f36bf7987c664d1122b58fe8bd95b8fc43 (patch)
treee31a9b624bbeaf093663c64d22a94d2185108f1b /src
parentdb06859d70db1ae60c3b70432b7e891407d8314d (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.lst10
-rw-r--r--src/mame/psion/etna.cpp132
-rw-r--r--src/mame/psion/etna.h44
-rw-r--r--src/mame/psion/psion5mx.cpp1451
-rw-r--r--src/mame/psion/psion5mx.h216
-rw-r--r--src/mame/psion/windermere.cpp990
-rw-r--r--src/mame/psion/windermere.h263
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