mirror of
https://github.com/holub/mame
synced 2025-06-04 20:06:28 +03:00
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:
parent
81bd070bf8
commit
f97a17275f
@ -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",
|
||||
|
499
src/devices/machine/psion_asic1.cpp
Normal file
499
src/devices/machine/psion_asic1.cpp
Normal 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;
|
||||
}
|
101
src/devices/machine/psion_asic1.h
Normal file
101
src/devices/machine/psion_asic1.h
Normal 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
|
377
src/devices/machine/psion_asic2.cpp
Normal file
377
src/devices/machine/psion_asic2.cpp
Normal 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;
|
||||
}
|
93
src/devices/machine/psion_asic2.h
Normal file
93
src/devices/machine/psion_asic2.h
Normal 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
|
188
src/devices/machine/psion_asic3.cpp
Normal file
188
src/devices/machine/psion_asic3.cpp
Normal 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;
|
||||
}
|
55
src/devices/machine/psion_asic3.h
Normal file
55
src/devices/machine/psion_asic3.h
Normal 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
|
@ -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
341
src/mame/psion/psion3.cpp
Normal 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 )
|
Loading…
Reference in New Issue
Block a user