New systems marked not working

------------------------------
Series 3 [Nigel Barnes, The Last Psion]

New clones marked not working
-----------------------------
Pocket Book [Nigel Barnes, The Last Psion]
Series 3s [Nigel Barnes, The Last Psion]
This commit is contained in:
Nigel Barnes 2023-05-17 22:13:06 +01:00
parent 81bd070bf8
commit f97a17275f
9 changed files with 1668 additions and 0 deletions

View File

@ -2897,6 +2897,9 @@ end
---------------------------------------------------
--
--@src/devices/machine/psion_asic1.h,MACHINES["PSION_ASIC"] = true
--@src/devices/machine/psion_asic2.h,MACHINES["PSION_ASIC"] = true
--@src/devices/machine/psion_asic3.h,MACHINES["PSION_ASIC"] = true
--@src/devices/machine/psion_asic4.h,MACHINES["PSION_ASIC"] = true
--@src/devices/machine/psion_asic5.h,MACHINES["PSION_ASIC"] = true
--@src/devices/machine/psion_asic9.h,MACHINES["PSION_ASIC"] = true
@ -2904,6 +2907,12 @@ end
if (MACHINES["PSION_ASIC"]~=null) then
files {
MAME_DIR .. "src/devices/machine/psion_asic1.cpp",
MAME_DIR .. "src/devices/machine/psion_asic1.h",
MAME_DIR .. "src/devices/machine/psion_asic2.cpp",
MAME_DIR .. "src/devices/machine/psion_asic2.h",
MAME_DIR .. "src/devices/machine/psion_asic3.cpp",
MAME_DIR .. "src/devices/machine/psion_asic3.h",
MAME_DIR .. "src/devices/machine/psion_asic4.cpp",
MAME_DIR .. "src/devices/machine/psion_asic4.h",
MAME_DIR .. "src/devices/machine/psion_asic5.cpp",

View File

@ -0,0 +1,499 @@
// license:BSD-3-Clause
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC1
ASIC1 is the main system controller chip for the SIBO architecture. It connects
directly to the 8086-based processor (i.e. the V30H) controlling all bus cycles
to and from the processor. This configuration effectively forms a micro-controller
like device that executes 8086 instruction codes. ASIC 1 is made up of a number of
functional blocks including a bus controller, a programmable timer, an eight input
interrupt controller, an LCD controller and the memory decoding circuitry.
******************************************************************************/
#include "emu.h"
#include "psion_asic1.h"
#include "screen.h"
#define VERBOSE 0
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
DEFINE_DEVICE_TYPE(PSION_ASIC1, psion_asic1_device, "psion_asic1", "Psion ASIC1")
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
psion_asic1_device::psion_asic1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PSION_ASIC1, tag, owner, clock)
, device_memory_interface(mconfig, *this)
, device_video_interface(mconfig, *this)
, m_space_config("program", ENDIANNESS_LITTLE, 16, 20, 0)
, m_tick_timer(nullptr)
, m_frc_timer(nullptr)
, m_watchdog_timer(nullptr)
, m_int_cb(*this)
, m_nmi_cb(*this)
, m_frcovl_cb(*this)
, m_laptop_mode(false)
{
}
//-------------------------------------------------
// memory_space_config - return a description of
// any address spaces owned by this device
//-------------------------------------------------
device_memory_interface::space_config_vector psion_asic1_device::memory_space_config() const
{
return space_config_vector{
std::make_pair(0, &m_space_config)
};
}
//-------------------------------------------------
// device_resolve_objects - resolve objects that
// may be needed for other devices to set
// initial conditions at start time
//-------------------------------------------------
void psion_asic1_device::device_resolve_objects()
{
m_int_cb.resolve_safe();
m_nmi_cb.resolve_safe();
m_frcovl_cb.resolve_safe();
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void psion_asic1_device::device_start()
{
m_space = &space();
m_tick_timer = timer_alloc(FUNC(psion_asic1_device::tick), this);
m_frc_timer = timer_alloc(FUNC(psion_asic1_device::frc), this);
m_watchdog_timer = timer_alloc(FUNC(psion_asic1_device::watchdog), this);
m_a1_status = 0x00;
save_item(NAME(m_a1_status));
save_item(NAME(m_a1_lcd_size));
save_item(NAME(m_a1_lcd_control));
save_item(NAME(m_a1_interrupt_status));
save_item(NAME(m_a1_interrupt_mask));
save_item(NAME(m_a1_protection_mode));
save_item(NAME(m_a1_protection_lower));
save_item(NAME(m_a1_protection_upper));
save_item(NAME(m_frc_count));
save_item(NAME(m_frc_reload));
save_item(NAME(m_watchdog_count));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void psion_asic1_device::device_reset()
{
m_tick_timer->adjust(attotime::from_hz(4), 0, attotime::from_hz(4));
m_frc_timer->adjust(attotime::from_hz(512000), 0, attotime::from_hz(512000));
m_watchdog_timer->adjust(attotime::from_hz(4), 0, attotime::from_hz(4));
m_frc_count = 0;
m_frc_reload = 0;
m_frc_ovl = 0;
m_watchdog_count = 0;
m_a1_interrupt_status = 0x00;
m_a1_interrupt_mask = 0x00;
m_a1_protection_mode = false;
m_a1_protection_lower = 0x00;
m_a1_protection_upper = 0x00;
}
TIMER_CALLBACK_MEMBER(psion_asic1_device::tick)
{
m_a1_interrupt_status |= 0x01; // Timer
update_interrupts();
}
TIMER_CALLBACK_MEMBER(psion_asic1_device::frc)
{
switch (--m_frc_count)
{
case 0x0000:
m_frc_ovl ^= 1;
m_frcovl_cb(m_frc_ovl);
m_a1_interrupt_status |= 0x20; // FrcExpired
update_interrupts();
break;
case 0xffff:
if (BIT(m_a1_status, 0)) // FrcMode
m_frc_count = m_frc_reload;
break;
}
}
TIMER_CALLBACK_MEMBER(psion_asic1_device::watchdog)
{
m_watchdog_count++;
m_watchdog_count &= 3;
if (m_watchdog_count == 3)
{
m_a1_status |= 0x0100; // WatchDogNmi
update_interrupts();
}
}
WRITE_LINE_MEMBER(psion_asic1_device::eint1_w)
{
if (state)
m_a1_interrupt_status |= 0x04; // ExpIntRightB
else
m_a1_interrupt_status &= ~0x04;
update_interrupts();
}
WRITE_LINE_MEMBER(psion_asic1_device::eint2_w)
{
if (state)
m_a1_interrupt_status |= 0x08; // ExpIntLeftA
else
m_a1_interrupt_status &= ~0x08;
update_interrupts();
}
WRITE_LINE_MEMBER(psion_asic1_device::eint3_w)
{
if (state)
m_a1_interrupt_status |= 0x10; // Asic2Int
else
m_a1_interrupt_status &= ~0x10;
update_interrupts();
}
WRITE_LINE_MEMBER(psion_asic1_device::enmi_w)
{
if (state)
m_a1_status |= 0x0200; // ExternalNmi
else
m_a1_status &= ~0x0200;
update_interrupts();
}
void psion_asic1_device::update_interrupts(bool address_trap)
{
bool irq = m_a1_interrupt_status & m_a1_interrupt_mask;
bool nmi = (m_a1_status & 0x0300) || address_trap;
m_int_cb(irq ? ASSERT_LINE : CLEAR_LINE);
m_nmi_cb(nmi ? ASSERT_LINE : CLEAR_LINE);
}
IRQ_CALLBACK_MEMBER(psion_asic1_device::inta_cb)
{
// IRQ Vector Name Description
// 0 0x78 TINT Tick interrupt at 2 or 32 Hz
// 1 0x79 EINT0 External interrupt usually connected to mains detect bit
// 2 0x7A EINT1 External interrupt from expansion port one
// 3 0x7B EINT2 External interrupt from expansion port two
// 4 0x7C EINT3 External interrupt from ASIC2
// 5 0x7D OVINT Timer overflow interrupt
// 6 0x7E SRXI SLD sound receive interrupt
// 7 0x7F STXI SLD sound transmit interrupt
uint8_t vector = 0x78;
for (int irq = 0; irq < 8; irq++)
{
if (m_a1_interrupt_status & m_a1_interrupt_mask & (1 << irq))
{
vector += irq;
break;
}
}
return vector;
}
//**************************************************************************
// READ/WRITE HANDLERS
//**************************************************************************
bool psion_asic1_device::is_protected(offs_t offset)
{
if (m_a1_protection_mode && (offset <= m_a1_protection_lower || offset > m_a1_protection_upper))
{
LOG("%s is_protected: %05x < %05x <= %05x\n", machine().describe_context(), m_a1_protection_lower, offset, m_a1_protection_upper);
update_interrupts(true);
return true;
}
return false;
}
uint16_t psion_asic1_device::mem_r(offs_t offset, uint16_t mem_mask)
{
return m_space->read_word(offset << 1, mem_mask);
}
void psion_asic1_device::mem_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
if (!is_protected(offset << 1))
m_space->write_word(offset << 1, data, mem_mask);
}
uint16_t psion_asic1_device::io_r(offs_t offset, uint16_t mem_mask)
{
uint16_t data = 0x00;
switch (offset << 1)
{
case 0x02: // A1Status
// b0 FrcMode
// b1 TickRate
// b2 FrcSource
// b3 Ram128
// b4 Ram512
// b5 LcdEnable
// b6 A1SldEnable
// b7 SldTx
// b8 WatchDogNmi
// b9 ExternalNmi
// b10 Rtc32Hz
// b11 ComboBusy
// b12 SldMsw
// b13 Rtc4Hz
// b14-b15 LcdData - LCD id as follows:
// 0 = Lcd640X400
// 1 = Lcd640X200Small
// 2 = Lcd640X200Big
// 3 = Lcd720X348
// 4 = Lcd160X80
data = m_a1_status;
data |= lcd_type() << 14;
LOG("%s io_r: A1Status => %04x\n", machine().describe_context(), data);
break;
case 0x06: // A1InterruptStatus
data = m_a1_interrupt_status;
LOG("%s io_r: A1InterruptStatus => %02x\n", machine().describe_context(), data);
break;
case 0x08: // A1InterruptMask
data = m_a1_interrupt_mask;
LOG("%s io_r: A1InterruptMask => %02x\n", machine().describe_context(), data);
break;
case 0x12: // A1FrcControl
data = m_frc_count;
LOG("%s io_r: A1FrcControl => %04x\n", machine().describe_context(), data);
break;
case 0x14: // A1ProtectionOff
if (!machine().side_effects_disabled())
{
//LOG("%s io_r: A1ProtectionOff => %04x\n", machine().describe_context(), data);
m_a1_protection_mode = false;
}
break;
default:
data = 0xffff;
LOG("%s io_r: Unhandled register %02x => %04x\n", machine().describe_context(), offset << 1, data);
break;
}
return data;
}
void psion_asic1_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
switch (offset << 1)
{
case 0x02: // A1Control
// b0 FrcMode
// b1 TickRate
// b2 FrcSource
// b3 Ram128
// b4 Ram512
// b5 LcdEnable
// b6 A1SldEnable
// b7 SldTx
LOG("%s io_w: A1Control <= %04x\n", machine().describe_context(), data);
if (BIT(data, 1) != BIT(m_a1_status, 1))
{
if (data & 0x02) // TickRate
m_tick_timer->adjust(attotime::zero, 0, attotime::from_hz(32.768)); // RTC from PS34
else
m_tick_timer->adjust(attotime::zero, 0, attotime::from_hz(4));
}
m_a1_status = (m_a1_status & 0xff00) | (data & 0xff);
break;
case 0x04: // A1LcdSize
// b0-b9 LcdEndOfFrame - (Total pixels in display / 128) - 1
// b10-b14 LcdNumberOfPixels - (No. pixels in line / 32) - 1
// b15 LcdMLineEnable - 1 to enable the M line magic.
LOG("%s io_w: A1LcdSize <= %04x, Pixels in line %d, Total pixels in display %d\n", machine().describe_context(), data, (BIT(data, 10, 5) + 1) * 32, (BIT(data, 0, 10) + 1) * 128);
m_a1_lcd_size = data;
break;
case 0x06: // A1LcdControl
// b0-b4 LcdRate - LCDCLK = SYSCLK / (2*(n+1))
// b5-b9 LcdMLineRate - 13
// b10-b11 LcdMode - 3 (Dual Screen mode)
LOG("%s io_w: A1LcdControl <= %04x, LCD clock %dHz, %s\n", machine().describe_context(), data, clock() * 4 / (screen().width() * screen().height() * 2 * (BIT(data, 0, 5) + 1)), BIT(data, 10, 2) == 3 ? "Dual screen" : "Single screen");
m_a1_lcd_control = data;
break;
case 0x08: // A1InterruptMask
// b0 Timer
// b1 Mains
// b2 ExpIntRightB
// b3 ExpIntLeftA
// b4 Asic2Int
// b5 FrcExpired
// b6 SldReceive
// b7 SldTransmit
LOG("%s io_w: A1InterruptMask <= %02x\n", machine().describe_context(), data);
m_a1_interrupt_mask = data & 0xff;
update_interrupts();
break;
case 0x0a: // A1NonSpecificEoi
LOG("%s io_w: A1NonSpecificEoi <= %04x\n", machine().describe_context(), data);
break;
case 0x0c: // A1TimerEoi
LOG("%s io_w: A1TimerEoi <= %04x\n", machine().describe_context(), data);
m_a1_interrupt_status &= ~0x01; // Timer
update_interrupts();
break;
case 0x0e: // A1FrcEoi
LOG("%s io_w: A1FrcEoi <= %04x\n", machine().describe_context(), data);
m_a1_interrupt_status &= ~0x20; // FrcExpired
update_interrupts();
break;
case 0x10: // A1ResetWatchDog
//LOG("% io_w: A1ResetWatchDog <= %04x\n", machine().describe_context(), data);
m_watchdog_count = 0;
break;
case 0x12: // A1FrcControl
LOG("%s io_w: A1FrcControl <= %04x\n", machine().describe_context(), data);
m_frc_reload = data;
m_frc_count = data;
break;
case 0x14: // A1ProtectionOn
//LOG("%s io_w: A1ProtectionOn <= %04x\n", machine().describe_context(), data);
m_a1_protection_mode = true;
break;
case 0x16: // A1ProtectionUpper
//LOG("%s io_w: A1ProtectionUpper <= %04x\n", machine().describe_context(), data);
m_a1_protection_upper = (data << 4) | 0x0f;
break;
case 0x18: // A1ProtectionLower
//LOG("%s io_w: A1ProtectionLower <= %04x\n", machine().describe_context(), data);
m_a1_protection_lower = data << 4;
break;
case 0x1a: // A1SoundLsw
LOG("%s io_w: A1SoundLsw <= %04x\n", machine().describe_context(), data);
break;
case 0x1c: // A1SoundMsw
LOG("%s io_w: A1SoundMsw <= %04x\n", machine().describe_context(), data);
break;
case 0x1e: // A1SoundControl
LOG("%s io_w: A1SoundControl <= %04x\n", machine().describe_context(), data);
break;
default:
LOG("%s io_w: Unhandled register %02x <= %04x\n", machine().describe_context(), offset << 1, data);
break;
}
}
//-------------------------------------------------
// LCD Controller
//-------------------------------------------------
uint8_t psion_asic1_device::lcd_type()
{
if (m_laptop_mode)
{
switch (screen().height())
{
case 400: return 0;
case 200: return 1;
}
}
return 0;
}
uint32_t psion_asic1_device::screen_update_single(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
return screen_update(screen, bitmap, cliprect, 1);
}
uint32_t psion_asic1_device::screen_update_dual(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
return screen_update(screen, bitmap, cliprect, 2);
}
uint32_t psion_asic1_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int screens)
{
if (m_a1_status & 0x0020) // LCD enable bit
{
pen_t const *const pens = screen.palette().pens();
offs_t videoram = m_laptop_mode ? 0xb8000 : 0x00400;
int const width = (BIT(m_a1_lcd_size, 10, 5) + 1) * 32;
int const height = screen.height() / screens;
for (int vmap = 0; vmap < screens; vmap++)
{
for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y / screens; y++)
{
for (int x = screen.visible_area().min_x; x <= (screen.visible_area().max_x / 8); x++)
{
uint8_t const pixels = m_space->read_byte(videoram + (vmap << 14) + (y * (width / 8)) + x);
uint16_t *p = &bitmap.pix((vmap * height) + y, x << 3);
for (int i = 0; i < 8; i++)
*p++ = pens[BIT(pixels, i)];
}
}
}
}
else
{
bitmap.fill(0, cliprect);
}
return 0;
}

View File

@ -0,0 +1,101 @@
// license:BSD-3-Clause
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC1
******************************************************************************/
#ifndef MAME_MACHINE_PSION_ASIC1_H
#define MAME_MACHINE_PSION_ASIC1_H
#pragma once
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> psion_asic1_device
class psion_asic1_device : public device_t,
public device_memory_interface,
public device_video_interface
{
public:
// construction/destruction
psion_asic1_device(const machine_config &mconfig, const char* tag, device_t* owner, uint32_t clock);
void set_laptop_mode(bool laptop) { m_laptop_mode = laptop; }
// callbacks
auto int_cb() { return m_int_cb.bind(); }
auto nmi_cb() { return m_nmi_cb.bind(); }
auto frcovl_cb() { return m_frcovl_cb.bind(); }
uint16_t mem_r(offs_t offset, uint16_t mem_mask);
void mem_w(offs_t offset, uint16_t data, uint16_t mem_mask);
uint16_t io_r(offs_t offset, uint16_t mem_mask);
void io_w(offs_t offset, uint16_t data, uint16_t mem_mask);
IRQ_CALLBACK_MEMBER(inta_cb);
DECLARE_WRITE_LINE_MEMBER(eint1_w);
DECLARE_WRITE_LINE_MEMBER(eint2_w);
DECLARE_WRITE_LINE_MEMBER(eint3_w);
DECLARE_WRITE_LINE_MEMBER(enmi_w);
uint32_t screen_update_single(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
uint32_t screen_update_dual(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
protected:
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual space_config_vector memory_space_config() const override;
private:
const address_space_config m_space_config;
address_space *m_space;
emu_timer *m_tick_timer;
emu_timer *m_frc_timer;
emu_timer *m_watchdog_timer;
TIMER_CALLBACK_MEMBER(tick);
TIMER_CALLBACK_MEMBER(frc);
TIMER_CALLBACK_MEMBER(watchdog);
void update_interrupts(bool address_trap = false);
bool is_protected(offs_t offset);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int plates);
uint16_t m_a1_status;
uint16_t m_a1_lcd_size;
uint16_t m_a1_lcd_control;
uint16_t m_frc_count;
uint16_t m_frc_reload;
int m_frc_ovl;
uint8_t m_watchdog_count;
bool m_a1_protection_mode;
uint32_t m_a1_protection_upper;
uint32_t m_a1_protection_lower;
uint8_t m_a1_interrupt_status;
uint8_t m_a1_interrupt_mask;
devcb_write_line m_int_cb;
devcb_write_line m_nmi_cb;
devcb_write_line m_frcovl_cb;
bool m_laptop_mode;
uint8_t lcd_type();
};
// device type definition
DECLARE_DEVICE_TYPE(PSION_ASIC1, psion_asic1_device)
#endif // MAME_MACHINE_PSION_ASIC1_H

View File

@ -0,0 +1,377 @@
// license:BSD-3-Clause
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC2
ASIC2 is the peripheral controller chip for the SIBO architecture. It contains
the system clock oscillator and controls switching between the standby and
operating states. ASIC2 provides an interface to the power supply, keyboard,
buzzer and SSDs. ASIC 2 includes the eight-channel SIBO serial protocol
controller and provides interface circuitry to both the reduced external and
extended internal peripheral expansion ports.
******************************************************************************/
#include "emu.h"
#include "psion_asic2.h"
#define VERBOSE 0
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
DEFINE_DEVICE_TYPE(PSION_ASIC2, psion_asic2_device, "psion_asic2", "Psion ASIC2")
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
psion_asic2_device::psion_asic2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PSION_ASIC2, tag, owner, clock)
, m_int_cb(*this)
, m_nmi_cb(*this)
, m_cbusy_cb(*this)
, m_buz_cb(*this)
, m_buzvol_cb(*this)
, m_dr_cb(*this)
, m_col_cb(*this)
, m_data_r(*this)
, m_data_w(*this)
{
}
//-------------------------------------------------
// device_resolve_objects - resolve objects that
// may be needed for other devices to set
// initial conditions at start time
//-------------------------------------------------
void psion_asic2_device::device_resolve_objects()
{
m_int_cb.resolve_safe();
m_nmi_cb.resolve_safe();
m_cbusy_cb.resolve_safe();
m_buz_cb.resolve_safe();
m_buzvol_cb.resolve_safe();
m_dr_cb.resolve_safe();
m_col_cb.resolve_safe(0xff);
m_data_r.resolve_all_safe(0x00);
m_data_w.resolve_all_safe();
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void psion_asic2_device::device_start()
{
m_a2_status = 0x01;
m_busy_timer = timer_alloc(FUNC(psion_asic2_device::busy), this);
save_item(NAME(m_a2_control1));
save_item(NAME(m_a2_control2));
save_item(NAME(m_a2_control3));
save_item(NAME(m_a2_serial_data));
save_item(NAME(m_a2_serial_control));
save_item(NAME(m_a2_interrupt_status));
save_item(NAME(m_a2_status));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void psion_asic2_device::device_reset()
{
m_a2_control1 = 0x00;
m_a2_control2 = 0x00;
m_a2_control3 = 0x00;
m_a2_serial_data = 0x00;
m_a2_serial_control = 0x00;
m_a2_interrupt_status = 0x00;
m_a2_channel_control = 0x00;
}
WRITE_LINE_MEMBER(psion_asic2_device::on_clr_w)
{
if (state)
m_a2_status |= 0x01; // A1OnKey
else
m_a2_status &= ~0x01;
update_interrupts();
}
WRITE_LINE_MEMBER(psion_asic2_device::dnmi_w)
{
if (state)
m_a2_interrupt_status |= 0x01; // DNMI
else
m_a2_interrupt_status &= ~0x01;
update_interrupts();
}
WRITE_LINE_MEMBER(psion_asic2_device::frcovl_w)
{
if (BIT(m_a2_control2, 4))
{
m_buz_cb(state);
}
}
WRITE_LINE_MEMBER(psion_asic2_device::reset_w)
{
if (!state)
m_a2_status |= 0x04; // A1ResetFlag
}
void psion_asic2_device::update_interrupts()
{
int irq = m_a2_status & 0x01;
int nmi = BIT(m_a2_interrupt_status, 0, 2) & BIT(m_a2_control3, 4, 2);
m_int_cb(irq ? ASSERT_LINE : CLEAR_LINE);
m_nmi_cb(nmi ? ASSERT_LINE : CLEAR_LINE);
}
TIMER_CALLBACK_MEMBER(psion_asic2_device::busy)
{
m_a2_status &= ~0x10; // clear data serial controller is busy
m_cbusy_cb(1);
}
//**************************************************************************
// READ/WRITE HANDLERS
//**************************************************************************
uint8_t psion_asic2_device::io_r(offs_t offset)
{
uint8_t data = 0x00;
switch (offset & 7)
{
case 0x02: // A2External - External status register
switch (m_a2_control1 & 0x0f)
{
case 0x0f: // all keyboard columns
for (int i = 0; i < 10; i++)
data |= m_col_cb(i);
break;
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0a:
data = m_col_cb((m_a2_control1 & 0x0f) - 1);
break;
default:
data = 0x00;
break;
}
LOG("%s io_r: A2External => %02x\n", machine().describe_context(), data);
break;
case 0x03: // A2InterruptStatus - Interrupt status register
// b0 DoorInterrupt - Status of pack doors, 1 if open
// b1 ExpansionInterrupt - Status of expansion interface doors, 1 if open
// b2 SlaveDataValid - Slave data valid, 1 if valid frame arrived
// b3 SlaveDataControl - Slave control or data frame, 1 if control frame
// b4 SlaveDataOverrun - Slave data overrun, 1 if overrun
data = m_a2_interrupt_status;
LOG("%s io_r: A2InterruptStatus => %02x\n", machine().describe_context(), data);
break;
case 0x04: // A2Status - Status register
// b0 A1OnKey - 1 if on key pressed
// b1 WakeUp - 1 if external wakeup valid
// b2 A1ResetFlag - 1 if system reset
// b3 SerialClockState - 1 if slave clock is high
// b4 SerialBusy - 1 while data serial controller is busy
// b5 A2Sdis - 1 if slave data signal is high
data = m_a2_status;
if (!machine().side_effects_disabled())
{
m_a2_status &= ~0x01; // clear A1OnKey
m_a2_status &= ~0x04; // clear A1ResetFlag
}
LOG("%s io_r: A2Status => %02x\n", machine().describe_context(), data);
break;
case 0x05: // A2SerialData - Serial channel read data register
data = m_a2_serial_data;
if ((m_a2_serial_control & 0x10) == 0x10)
m_a2_serial_data = receive_frame();
LOG("%s io_r: A2SerialData => %02x\n", machine().describe_context(), data);
break;
case 0x06: // A2KeyData - Keyboard poll register
data = m_col_cb(m_a2_control1 & 0x0f);
LOG("%s io_r: A2KeyData => %02x\n", machine().describe_context(), data);
break;
case 0x07: // A2SlaveData - Slave data read register
data = 0x00;
LOG("%s io_r: A2SlaveData => %02x\n", machine().describe_context(), data);
break;
default:
LOG("%s io_r: Unhandled register %02x => %02x\n", machine().describe_context(), offset, data);
break;
}
return data;
}
void psion_asic2_device::io_w(offs_t offset, uint8_t data)
{
switch (offset & 7)
{
case 0x02: // A2Control1 - Control register 1
// b0-b3 KeyScan - Values 0-15 drive the keyboard poll columns
// b4-b5 SerialClockRate - Sets the clock frequency for channels 1-4 and 7 as below:
// 0 = ClockRateMedium 1.536 MHz
// 2 = ClockRateSlow 256 KHz
// 3 = ClockRateFast 3.84 MHz
LOG("%s io_w: A2Control1 <= %02x\n", machine().describe_context(), data);
m_a2_control1 = data;
//m_a2_external = m_col_cb(data & 0x0f);
break;
case 0x03: // A2Control2 - Control register 2
// b0 DigitizerEnable - 1 to enable digitizer drivers
// b1 XySwitch - 0 to drive digitizer X scan, 1 to drive Y
// b2 BuzzerToggle - Toggles the piezo speaker
// b3 BuzzerVolume - 1 if loud buzzer volume, 0 is soft
// b4 BuzzerMode - Piezo driving mode, 0 - toggled by BZTOG, 1 - driven by FRC
// b5 ClockEnable5 - Enable continuous clock on serial channel 5
// b6 ClockEnable6 - Enable continuous clock on serial channel 6
// b7 ClockEnable7 - Enable continuous clock on serial channel 7
LOG("%s io_w: A2Control2 <= %02x\n", machine().describe_context(), data);
m_a2_control2 = data;
m_dr_cb(BIT(data, 1));
if (!BIT(data, 4))
{
m_buz_cb(BIT(data, 2));
}
m_buzvol_cb(BIT(data, 3));
break;
case 0x04: // A2Control3 - Control register 3
// b0 SerialNull - 1 to send a null frame
// b1 Ps34Acknowledge - 1 to reset PS34 on power up
// b2 A2SldEnable - 1 to enable SLD bus clock
// b3 SerialEnable - 1 to enable access to pack channels 1-4
// b4 DoorEnable - 1 to enable pack door NMIs
// b5 ExpansionEnable - 1 to enable expansion door NMIs
// b6 VhControl - 1 to enable VPP to packs
// b7 ElEnable - 1 to enable LCD back light
LOG("%s io_w: A2Control3 <= %02x\n", machine().describe_context(), data);
m_a2_control3 = data;
if (BIT(m_a2_control3, 0))
transmit_frame(NULL_FRAME);
break;
case 0x05: // A2SerialData - Serial channel write data register
LOG("%s io_w: A2SerialData <= %02x\n", machine().describe_context(), data);
if ((m_a2_serial_control & 0xc0) == 0x80)
transmit_frame(DATA_FRAME | data);
break;
case 0x06: // A2SerialControl - Serial channel write control register
// WriteSingle 10000000b; ReadSingle 11000000b
// WriteMulti 10010000b; ReadMulti 11010000b
// Reset 00000000b; Select 01000000b
// Asic2SlaveId 001h; Asic5PackId 002h
// Asic5NormalId 003h; Asic6Id 004h
// Asic8Id 005h; Asic4Id 006h
LOG("%s io_w: A2SerialControl <= %02x\n", machine().describe_context(), data);
m_a2_serial_control = data;
transmit_frame(CONTROL_FRAME | data);
if ((m_a2_serial_control & 0x40) == 0x40)
m_a2_serial_data = receive_frame();
break;
case 0x07: // A2ChannelControl - Serial channel select register
// b0 Pack1Enable - 1 to select pack 1
// b1 Pack2Enable - 1 to select pack 2
// b2 Pack3Enable - 1 to select pack 3
// b3 Pack4Enable - 1 to select pack 4
// b4-b6 ChannelSelect - 0-7 to select channel 0,5-8 as below:
// 4 = PK0, 5 = PK5, 6 = PK6, 7 = PK7
// b7 MultiplexEnable - 1 to loop slave channel to pack channel
LOG("%s io_w: A2ChannelControl <= %02x Channels %c %c %c %c %c %c %c %c\n", machine().describe_context(), data,
BIT(data, 4, 3) == 4 ? '0' : ' ',
BIT(data, 0) ? '1' : ' ',
BIT(data, 1) ? '2' : ' ',
BIT(data, 2) ? '3' : ' ',
BIT(data, 3) ? '4' : ' ',
BIT(data, 4, 3) == 5 ? '5' : ' ',
BIT(data, 4, 3) == 6 ? '6' : ' ',
BIT(data, 4, 3) == 7 ? '7' : ' ');
m_a2_channel_control = data;
break;
default:
LOG("%s io_w: Unhandled register %02x <= %02x\n", machine().describe_context(), offset, data);
break;
}
}
//-------------------------------------------------
// SIBO Serial Protocol Controller
//-------------------------------------------------
bool psion_asic2_device::channel_active(int channel)
{
switch (channel)
{
case 0:
return BIT(m_a2_channel_control, 4, 3) == 4;
case 1: case 2: case 3: case 4:
return BIT(m_a2_channel_control, channel - 1);
case 5: case 6: case 7:
return BIT(m_a2_channel_control, 4, 3) == channel;
}
return false;
}
void psion_asic2_device::transmit_frame(uint16_t data)
{
m_a2_status |= 0x10; // set data serial controller is busy
m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2));
m_cbusy_cb(0);
for (int ch = 0; ch < 8; ch++)
{
if (channel_active(ch))
{
LOG("%s Channel %d Transmit %s frame %02x\n", machine().describe_context(), ch, (data & DATA_FRAME) ? "Data" : (data & CONTROL_FRAME) ? "Control" : "Null", data & 0xff);
m_data_w[ch](data);
}
}
}
uint8_t psion_asic2_device::receive_frame()
{
uint8_t data = 0x00;
m_a2_status |= 0x10; // set data serial controller is busy
m_busy_timer->adjust(attotime::from_ticks(12, clock() / 2));
m_cbusy_cb(0);
for (int ch = 0; ch < 8; ch++)
{
if (channel_active(ch))
{
data |= m_data_r[ch]();
LOG("%s Channel %d Receive Data frame %02x\n", machine().describe_context(), ch, data);
}
}
return data;
}

View File

@ -0,0 +1,93 @@
// license:BSD-3-Clause
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC2
******************************************************************************/
#ifndef MAME_MACHINE_PSION_ASIC2_H
#define MAME_MACHINE_PSION_ASIC2_H
#pragma once
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> psion_asic2_device
class psion_asic2_device : public device_t
{
public:
// construction/destruction
psion_asic2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// callbacks
auto int_cb() { return m_int_cb.bind(); }
auto nmi_cb() { return m_nmi_cb.bind(); }
auto cbusy_cb() { return m_cbusy_cb.bind(); }
auto buz_cb() { return m_buz_cb.bind(); }
auto buzvol_cb() { return m_buzvol_cb.bind(); }
auto dr_cb() { return m_dr_cb.bind(); }
auto col_cb() { return m_col_cb.bind(); }
template <unsigned N> auto data_r() { static_assert(N < 8); return m_data_r[N].bind(); }
template <unsigned N> auto data_w() { static_assert(N < 8); return m_data_w[N].bind(); }
uint8_t io_r(offs_t offset);
void io_w(offs_t offset, uint8_t data);
DECLARE_WRITE_LINE_MEMBER(on_clr_w);
DECLARE_WRITE_LINE_MEMBER(dnmi_w);
DECLARE_WRITE_LINE_MEMBER(frcovl_w);
DECLARE_WRITE_LINE_MEMBER(reset_w);
protected:
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
private:
void update_interrupts();
uint8_t m_a2_control1;
uint8_t m_a2_control2;
uint8_t m_a2_control3;
uint8_t m_a2_serial_data;
uint8_t m_a2_serial_control;
uint8_t m_a2_interrupt_status;
uint8_t m_a2_status;
uint8_t m_a2_channel_control;
//uint8_t m_a2_external;
devcb_write_line m_int_cb;
devcb_write_line m_nmi_cb;
devcb_write_line m_cbusy_cb;
devcb_write_line m_buz_cb;
devcb_write_line m_buzvol_cb;
devcb_write_line m_dr_cb;
devcb_read8 m_col_cb;
devcb_read8::array<8> m_data_r;
devcb_write16::array<8> m_data_w;
emu_timer *m_busy_timer;
TIMER_CALLBACK_MEMBER(busy);
bool channel_active(int channel);
void transmit_frame(uint16_t data);
uint8_t receive_frame();
static constexpr uint16_t NULL_FRAME = 0x000;
static constexpr uint16_t CONTROL_FRAME = 0x100;
static constexpr uint16_t DATA_FRAME = 0x200;
};
// device type definition
DECLARE_DEVICE_TYPE(PSION_ASIC2, psion_asic2_device)
#endif // MAME_MACHINE_PSION_ASIC2_H

View File

@ -0,0 +1,188 @@
// license:BSD-3-Clause
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC3
MC and HC power supplies are based on a full custom liner ASIC known as ASIC3.
This custom chip is manufactured by Maxim and has the Maxim part number MAX616.
TODO:
- Battery status readings, maybe different analogue channel.
- Resolve ambiguity about status register, S3 and MC/HC machines expect different data.
******************************************************************************/
#include "emu.h"
#include "psion_asic3.h"
#define VERBOSE 0
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
DEFINE_DEVICE_TYPE(PSION_ASIC3, psion_asic3_device, "psion_asic3", "Psion ASIC3")
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
psion_asic3_device::psion_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PSION_ASIC3, tag, owner, clock)
, m_adin_cb(*this)
{
}
//-------------------------------------------------
// device_resolve_objects - resolve objects that
// may be needed for other devices to set
// initial conditions at start time
//-------------------------------------------------
void psion_asic3_device::device_resolve_objects()
{
m_adin_cb.resolve_safe(0);
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void psion_asic3_device::device_start()
{
save_item(NAME(m_a3_status));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void psion_asic3_device::device_reset()
{
m_a3_status = 0x00;
}
//**************************************************************************
// READ/WRITE HANDLERS
//**************************************************************************
void psion_asic3_device::data_w(uint16_t data)
{
switch (data & 0x300)
{
case NULL_FRAME:
break;
case CONTROL_FRAME:
m_sibo_control = data & 0xff;
switch (m_sibo_control & 0xc0)
{
case 0x80: // SerialWrite
break;
}
break;
case DATA_FRAME:
data &= 0xff;
switch (m_sibo_control & 0x0f)
{
case 0x01: // A3Control1
// b0-b4 DtoaBits
// b5 Vcc3Enable LCD
// b6 Vcc4Enable Sound subsystem
// b7 Vcc5Enable SSDs
LOG("%s data_w: A3Control1 register %02x\n", machine().describe_context(), data);
m_a3_control1 = data;
break;
case 0x02: // A3Setup
LOG("%s data_w: A3Setup register %02x\n", machine().describe_context(), data);
break;
case 0x03: // A3Control2
// b0 Vee1Enable LCD
// b1 Vee2Enable Sound subsystem
// b2 VhEnable
// b3 Vee1SoftStart
// b4 Vee2SoftStart
// b5 VhSoftStart
// b6-b7 AnalogueMultiplex
LOG("%s data_w: A3Control2 register %02x\n", machine().describe_context(), data);
m_a3_control2 = data;
break;
case 0x04: // A3Dummy1
LOG("%s data_w: A3Dummy1 register %02x\n", machine().describe_context(), data);
break;
case 0x07: // A3Control3
// b0 xDummy1
// b1 OffEnable
// b2 AdcReadHighEnable
LOG("%s data_w: A3Control3 register %02x\n", machine().describe_context(), data);
m_a3_control3 = data;
break;
default:
LOG("%s data_w: Unhandled register %02x\n", machine().describe_context(), m_sibo_control & 0x0f);
break;
}
}
}
uint8_t psion_asic3_device::data_r()
{
uint8_t data = 0x00;
switch (m_sibo_control & 0xc0)
{
case 0x40: // SerialSelect
if (m_sibo_control == 0x43) // A3SelectId
data = 0x80; // A3InfoByte
break;
case 0xc0: // SerialRead
switch (m_sibo_control & 0x0f)
{
case 0x00: // A3Adc
// A3AdcLsbR
// b0-b6 OtherBits
// b7 InvertedBit
// A3AdcMsbR
// b0-b3 AdcBits
// b4 Overrange
// b5 Polarity
if (BIT(m_a3_control3, 2)) // AdcReadHighEnable
data = BIT(m_adin_cb(), 8, 4);
else
data = (m_adin_cb() & 0xff) ^ 0x80;
LOG("%s data_r: A3Adc register %02x\n", machine().describe_context(), data);
break;
case 0x0d: // A3Status
// b0-b2 Admsb
// b3 Nc
// b4 Penup
// b5 Vhready
// b6 ColdStart
// b7 PowerFail
// b0 ColdStart
// b1 PowerFail
data = 0x40;
LOG("%s data_r: A3Status register %02x\n", machine().describe_context(), data);
break;
default:
LOG("%s data_r: Unhandled register %02x\n", machine().describe_context(), m_sibo_control & 0x0f);
break;
}
break;
}
return data;
}

View File

@ -0,0 +1,55 @@
// license:BSD-3-Clause
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion ASIC3
******************************************************************************/
#ifndef MAME_MACHINE_PSION_ASIC3_H
#define MAME_MACHINE_PSION_ASIC3_H
#pragma once
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> psion_asic3_device
class psion_asic3_device : public device_t
{
public:
psion_asic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
// callbacks
auto adin_cb() { return m_adin_cb.bind(); }
void data_w(uint16_t data);
uint8_t data_r();
protected:
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
private:
static constexpr uint16_t NULL_FRAME = 0x000;
static constexpr uint16_t CONTROL_FRAME = 0x100;
static constexpr uint16_t DATA_FRAME = 0x200;
devcb_read16 m_adin_cb;
uint8_t m_sibo_control;
uint8_t m_a3_control1;
uint8_t m_a3_control2;
uint8_t m_a3_control3;
uint8_t m_a3_status;
};
// device type definition
DECLARE_DEVICE_TYPE(PSION_ASIC3, psion_asic3_device)
#endif // MAME_MACHINE_PSION_ASIC3_H

View File

@ -37721,6 +37721,11 @@ psionp350 //
psionp464 //
psionxp //
@source:psion/psion3.cpp
pocketbk // 1992 Acorn Pocket Book
psion3 // 1991 Psion Series 3
psion3s // 1994 Psion Series 3s
@source:psion/psion3a.cpp
pocketbk2 // 1994 Acorn Pocket Book II
psion3a // 1993 Psion Series 3a

341
src/mame/psion/psion3.cpp Normal file
View File

@ -0,0 +1,341 @@
// license:BSD-3-Clause
// copyright-holders:Nigel Barnes
/******************************************************************************
Psion Series 3
TODO:
- battery backed RAM
- DTMF tone generator
******************************************************************************/
#include "emu.h"
#include "cpu/nec/nec.h"
#include "machine/psion_asic1.h"
#include "machine/psion_asic2.h"
#include "machine/psion_ssd.h"
#include "machine/ram.h"
#include "sound/pcd3311.h"
#include "sound/spkrdev.h"
#include "bus/psion/sibo/slot.h"
#include "emupal.h"
#include "screen.h"
#include "softlist_dev.h"
#include "speaker.h"
#include "utf8.h"
namespace {
class psion3_state : public driver_device
{
public:
psion3_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_asic1(*this, "asic1")
, m_asic2(*this, "asic2")
, m_ram(*this, "ram")
, m_palette(*this, "palette")
, m_keyboard(*this, "COL%u", 0U)
, m_dtmf(*this, "dtmf")
, m_speaker(*this, "speaker")
, m_ssd(*this, "ssd%u", 1U)
, m_sibo(*this, "sibo")
{ }
void psion3(machine_config &config);
void psion3s(machine_config &config);
DECLARE_INPUT_CHANGED_MEMBER(key_on);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
private:
required_device<cpu_device> m_maincpu;
required_device<psion_asic1_device> m_asic1;
required_device<psion_asic2_device> m_asic2;
required_device<ram_device> m_ram;
required_device<palette_device> m_palette;
required_ioport_array<10> m_keyboard;
required_device<pcd3311_device> m_dtmf;
required_device<speaker_sound_device> m_speaker;
required_device_array<psion_ssd_device, 2> m_ssd;
required_device<psion_sibo_slot_device> m_sibo;
void palette_init(palette_device &palette);
void mem_map(address_map &map);
void io_map(address_map &map);
void asic1_map(address_map &map);
};
void psion3_state::machine_start()
{
m_asic1->space(0).install_ram(0, m_ram->mask(), m_ram->pointer());
}
void psion3_state::machine_reset()
{
}
void psion3_state::mem_map(address_map &map)
{
map(0x00000, 0xfffff).rw(m_asic1, FUNC(psion_asic1_device::mem_r), FUNC(psion_asic1_device::mem_w));
}
void psion3_state::io_map(address_map &map)
{
map(0x0000, 0x001f).rw(m_asic1, FUNC(psion_asic1_device::io_r), FUNC(psion_asic1_device::io_w));
map(0x0080, 0x008f).rw(m_asic2, FUNC(psion_asic2_device::io_r), FUNC(psion_asic2_device::io_w)).umask16(0x00ff);
//map(0x0100, 0x01ff).lr8(NAME([]() { return 0xff; })); // w: enable Vcc lines?
map(0x0200, 0x02ff).w(m_dtmf, FUNC(pcd3311_device::write));
}
void psion3_state::asic1_map(address_map &map)
{
map(0x80000, 0xfffff).rom().region("flash", 0);
}
static INPUT_PORTS_START( psion3 )
PORT_START("COL0")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_NAME("1 ! Off")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME(UTF8_RIGHT" End")
PORT_START("COL1")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') PORT_CHAR('#')
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
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_4) PORT_CHAR('4') PORT_CHAR('$') PORT_CHAR('~')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_NAME("Help Dial")
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (R)")
PORT_START("COL2")
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_Z) PORT_CHAR('z') PORT_CHAR('Z')
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_CHAR('\'')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('?') PORT_CHAR('}')
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('+') PORT_CHAR('=')
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
PORT_START("COL3")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_CHAR(UCHAR_MAMEKEY(F11)) PORT_NAME("Menu")
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_T) PORT_CHAR('t') PORT_CHAR('T')
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_9) PORT_CHAR('9') PORT_CHAR('(') PORT_CHAR('[')
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_CHAR(']')
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME(UTF8_LEFT" Home")
PORT_START("COL4")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME(UTF8_UP" Pg Up")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_NAME("Caps Lock")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME(UTF8_DOWN" Pg Dn")
PORT_START("COL5")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(0xa3) PORT_CHAR('\\')
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_CHAR('{')
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR('*') PORT_CHAR(':')
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
PORT_START("COL6")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) PORT_NAME("Control")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("Shift (L)")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("Psion")
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(0x08) PORT_NAME("Delete")
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("Enter")
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_START("COL7")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("Data")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("Time")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("Program")
PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT(0x20, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT(0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(0x09) PORT_NAME("Tab")
PORT_START("COL8")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("Word")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("World")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT(0xf8, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_START("COL9")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("System")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("Agenda")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("Calc")
PORT_BIT(0xf8, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_START("ESC")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) PORT_NAME("Esc On") PORT_CHANGED_MEMBER(DEVICE_SELF, psion3_state, key_on, 0)
INPUT_PORTS_END
static INPUT_PORTS_START( psion3s )
PORT_INCLUDE(psion3)
PORT_MODIFY("COL7")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("Sheet")
INPUT_PORTS_END
static INPUT_PORTS_START( pocketbk )
PORT_INCLUDE(psion3)
PORT_MODIFY("COL1")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10)) PORT_NAME("Help")
PORT_MODIFY("COL6")
PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("Acorn")
PORT_MODIFY("COL7")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_NAME("Cards")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_NAME("Time")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8)) PORT_NAME("Key2")
PORT_MODIFY("COL8")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_NAME("Write")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6)) PORT_NAME("Calc")
PORT_MODIFY("COL9")
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_NAME("Desktop")
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_NAME("Abacus")
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7)) PORT_NAME("Key1")
INPUT_PORTS_END
INPUT_CHANGED_MEMBER(psion3_state::key_on)
{
if (newval)
{
m_asic2->on_clr_w(newval);
}
}
void psion3_state::palette_init(palette_device &palette)
{
palette.set_pen_color(0, rgb_t(170, 180, 160));
palette.set_pen_color(1, rgb_t(80, 75, 50));
}
void psion3_state::psion3(machine_config &config)
{
V30(config, m_maincpu, 7.68_MHz_XTAL / 2);
m_maincpu->set_addrmap(AS_PROGRAM, &psion3_state::mem_map);
m_maincpu->set_addrmap(AS_IO, &psion3_state::io_map);
m_maincpu->set_irq_acknowledge_callback(m_asic1, FUNC(psion_asic1_device::inta_cb));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD));
screen.set_size(240, 80);
screen.set_visarea_full();
screen.set_refresh_hz(66);
screen.set_screen_update(m_asic1, FUNC(psion_asic1_device::screen_update_single));
screen.set_palette(m_palette);
PALETTE(config, "palette", FUNC(psion3_state::palette_init), 2);
PSION_ASIC1(config, m_asic1, 7.68_MHz_XTAL);
m_asic1->set_laptop_mode(false);
m_asic1->set_addrmap(0, &psion3_state::asic1_map);
m_asic1->int_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_asic1->nmi_cb().set_inputline(m_maincpu, INPUT_LINE_NMI);
m_asic1->frcovl_cb().set(m_asic2, FUNC(psion_asic2_device::frcovl_w));
PSION_ASIC2(config, m_asic2, 7.68_MHz_XTAL);
m_asic2->int_cb().set(m_asic1, FUNC(psion_asic1_device::eint3_w));
m_asic2->nmi_cb().set(m_asic1, FUNC(psion_asic1_device::enmi_w));
m_asic2->cbusy_cb().set_inputline(m_maincpu, NEC_INPUT_LINE_POLL);
m_asic2->buz_cb().set(m_speaker, FUNC(speaker_sound_device::level_w));
m_asic2->buzvol_cb().set([this](int state) { m_speaker->set_output_gain(ALL_OUTPUTS, state ? 1.0 : 0.25); });
m_asic2->col_cb().set([this](uint8_t data) { return m_keyboard[data]->read(); });
m_asic2->data_r<1>().set(m_ssd[0], FUNC(psion_ssd_device::data_r)); // SSD Pack 1
m_asic2->data_w<1>().set(m_ssd[0], FUNC(psion_ssd_device::data_w));
m_asic2->data_r<2>().set(m_ssd[1], FUNC(psion_ssd_device::data_r)); // SSD Pack 2
m_asic2->data_w<2>().set(m_ssd[1], FUNC(psion_ssd_device::data_w));
m_asic2->data_r<7>().set(m_sibo, FUNC(psion_sibo_slot_device::data_r)); // SIBO expansion port
m_asic2->data_w<7>().set(m_sibo, FUNC(psion_sibo_slot_device::data_w));
RAM(config, m_ram).set_default_size("256K").set_extra_options("128K");
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00); // Piezo buzzer
PCD3311(config, m_dtmf, 3'580'000).add_route(ALL_OUTPUTS, "mono", 0.25); // PCD3311CT
PSION_SSD(config, m_ssd[0]);
m_ssd[0]->door_cb().set(m_asic2, FUNC(psion_asic2_device::dnmi_w));
PSION_SSD(config, m_ssd[1]);
m_ssd[1]->door_cb().set(m_asic2, FUNC(psion_asic2_device::dnmi_w));
PSION_SIBO_SLOT(config, m_sibo, psion_sibo_devices, nullptr);
//m_sibo->int_cb().set(m_asic2, FUNC(psion_asic2_device::eint_w)); // TODO: unknown interrupt line
SOFTWARE_LIST(config, "ssd_list").set_original("psion_ssd").set_filter("S3");
}
void psion3_state::psion3s(machine_config &config)
{
psion3(config);
m_ram->set_default_size("256K").set_extra_options("");
}
ROM_START(psion3)
ROM_REGION16_LE(0x80000, "flash", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS(0, "177f", "V1.77F/ENG 221091")
ROMX_LOAD("3504-3002-01_19-11-91v1.77f_eng.bin", 0x00000, 0x20000, CRC(73ba99fa) SHA1(1b3f7b2da9cc2f189e88a9aa01fdb6fad7598925), ROM_BIOS(0))
ROMX_LOAD("3504-3001-01_19-11-91v1.77f_eng.bin", 0x40000, 0x40000, CRC(e868c250) SHA1(48cce7dd219fb776bffe247c48ba070a89bff121), ROM_BIOS(0))
ROM_END
ROM_START(psion3s)
ROM_REGION16_LE(0x80000, "flash", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS(0, "191f", "V1.91F/ENG 140694")
ROMX_LOAD("s3_v1.91f_eng.bin", 0x00000, 0x80000, CRC(8b4cfa7a) SHA1(582ffba8ec81960b2db283ef0c280a6d8444414f), ROM_BIOS(0))
ROM_END
ROM_START(pocketbk)
ROM_REGION16_LE(0x80000, "flash", ROMREGION_ERASEFF)
ROM_SYSTEM_BIOS(0, "191f", "V1.91F/ACN 270892")
ROMX_LOAD("pb_v1.91f_acn.bin", 0x00000, 0x80000, CRC(875a804b) SHA1(9db07b3de9bcb9cc0c56c9a6fb35b9653eba68b3), ROM_BIOS(0))
ROM_END
} // anonymous namespace
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1991, psion3, 0, 0, psion3, psion3, psion3_state, empty_init, "Psion", "Series 3", MACHINE_NOT_WORKING )
COMP( 1992, pocketbk, psion3, 0, psion3s, pocketbk, psion3_state, empty_init, "Acorn Computers", "Pocket Book", MACHINE_NOT_WORKING )
COMP( 1994, psion3s, psion3, 0, psion3s, psion3s, psion3_state, empty_init, "Psion", "Series 3s", MACHINE_NOT_WORKING )