// license:BSD-3-Clause
// copyright-holders:Sandro Ronco
/****************************************************************************
psion_pack.c
Psion Organiser II Datapack emulation
Datapack pinout from Psion's documentation
__ __
SD1 1 | \/ | 2 SD0
SD3 3 | | 4 SD2
SD5 5 | | 6 SD4
SD7 7 | | 8 SD6
SMR 9 | | 10 SCLK
SOE_B 11 | | 12 SS_B
GND 13 | | 14 SPGM_B
SVCC 15 |______| 16 SVPP
****************************************************************************/
#include "emu.h"
#include "psion_pack.h"
// Datapack control lines
#define DP_LINE_CLOCK 0x01
#define DP_LINE_RESET 0x02
#define DP_LINE_PROGRAM 0x04
#define DP_LINE_OUTPUT_ENABLE 0x08
#define DP_LINE_SLOT_SELECT 0x10
// Datapack ID
#define DP_ID_EPROM 0x02
#define DP_ID_PAGED 0x04
#define DP_ID_WRITE 0x08
#define DP_ID_BOOT 0x10
#define DP_ID_COPY 0x20
#define OPK_HEAD_SIZE 6
OPTION_GUIDE_START( datapack_option_guide )
OPTION_INT('S', "size", "Datapack size" )
OPTION_INT('R', "ram", "RAM/EPROM" )
OPTION_INT('P', "paged", "Paged" )
OPTION_INT('W', "protect", "Write-protected" )
OPTION_INT('B', "boot", "Bootable" )
OPTION_INT('C', "copy", "Copyable" )
OPTION_GUIDE_END
static const char *datapack_option_spec =
"S1/2/4/[8]/16;R0/[1];P[0]/1;W[0]/1;B[0]/1;C0/[1]";
// device type definition
DEFINE_DEVICE_TYPE(PSION_DATAPACK, datapack_device, "datapack", "Psion Datapack")
//-------------------------------------------------
// datapack_device - constructor
//-------------------------------------------------
datapack_device::datapack_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PSION_DATAPACK, tag, owner, clock)
, device_image_interface(mconfig, *this)
{
}
//-------------------------------------------------
// datapack_device - destructor
//-------------------------------------------------
datapack_device::~datapack_device()
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void datapack_device::device_start()
{
call_unload();
}
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void datapack_device::device_config_complete()
{
add_format("opk", "Psion Datapack image", "opk", datapack_option_spec);
}
//-------------------------------------------------
// option_guide for create new image
//-------------------------------------------------
const util::option_guide &datapack_device::create_option_guide() const
{
return datapack_option_guide;
}
/*-------------------------------------------------
update the internal state
-------------------------------------------------*/
void datapack_device::update()
{
uint32_t pack_addr = m_counter + ((m_id & DP_ID_PAGED) ? (m_page << 8) : 0);
// if the datapack is 128k or more is treated as segmented
if (m_size >= 0x10)
pack_addr += (m_segment << 14);
if (pack_addr < (m_size << 13))
{
if ((m_control & DP_LINE_OUTPUT_ENABLE) && !(m_control & DP_LINE_RESET))
{
// write data
if (!loaded_through_softlist() && (m_id & DP_ID_WRITE))
{
fseek(pack_addr + OPK_HEAD_SIZE, SEEK_SET);
fwrite(&m_data, 1);
}
}
else if ((m_control & DP_LINE_OUTPUT_ENABLE) && (m_control & DP_LINE_RESET))
{
// write datapack segment
if (m_size <= 0x10)
m_segment = m_data & 0x07;
else if (m_size <= 0x20)
m_segment = m_data & 0x0f;
else if (m_size <= 0x40)
m_segment = m_data & 0x1f;
else if (m_size <= 0x80)
m_segment = m_data & 0x3f;
else
m_segment = m_data;
}
else if (!(m_control & DP_LINE_OUTPUT_ENABLE) && !(m_control & DP_LINE_RESET))
{
// read data
if ((pack_addr + OPK_HEAD_SIZE) < length())
{
fseek(pack_addr + OPK_HEAD_SIZE, SEEK_SET);
fread(&m_data, 1);
}
else
{
m_data = 0xff;
}
}
else if (!(m_control & DP_LINE_OUTPUT_ENABLE) && (m_control & DP_LINE_RESET))
{
// read datapack ID
if ((m_id & DP_ID_EPROM) || loaded_through_softlist())
m_data = m_id;
else
m_data = 0x01; // for identify RAM pack
}
}
}
/*-------------------------------------------------
read datapack data lines
-------------------------------------------------*/
uint8_t datapack_device::data_r()
{
return (!(m_control & DP_LINE_SLOT_SELECT)) ? m_data : 0;
}
/*-------------------------------------------------
write datapack data lines
-------------------------------------------------*/
void datapack_device::data_w(uint8_t data)
{
if (is_loaded())
{
m_data = data;
// updates the internal state
if (!(data & DP_LINE_SLOT_SELECT))
update();
}
}
/*-------------------------------------------------
read datapack control lines
-------------------------------------------------*/
uint8_t datapack_device::control_r()
{
return m_control;
}
/*-------------------------------------------------
write datapack control lines
-------------------------------------------------*/
void datapack_device::control_w(uint8_t data)
{
if (is_loaded())
{
if ((m_control & DP_LINE_CLOCK) != (data & DP_LINE_CLOCK))
{
// increments the counter
m_counter++;
if (m_counter >= ((m_id & DP_ID_PAGED) ? 0x100 : (m_size << 13)))
m_counter = 0;
}
if ((m_control & DP_LINE_PROGRAM) && !(data & DP_LINE_PROGRAM))
{
// increments the page
m_page++;
if (m_page >= (m_size << 5))
m_page = 0;
}
if (data & DP_LINE_RESET)
{
// reset counter and page
m_counter = 0;
m_page = 0;
}
m_control = data;
// updates the internal state
if (!(data & DP_LINE_SLOT_SELECT))
update();
}
}
/*-------------------------------------------------
DEVICE_IMAGE_LOAD( datapack )
-------------------------------------------------*/
image_init_result datapack_device::call_load()
{
uint8_t data[0x10];
fread(data, 0x10);
// check the OPK head
if(strncmp((const char*)data, "OPK", 3))
return image_init_result::FAIL;
// get datapack ID and size
m_id = data[OPK_HEAD_SIZE + 0];
m_size = data[OPK_HEAD_SIZE + 1];
return image_init_result::PASS;
}
/*-------------------------------------------------
DEVICE_IMAGE_CREATE( datapack )
-------------------------------------------------*/
image_init_result datapack_device::call_create(int format_type, util::option_resolution *create_args)
{
static const uint8_t opk_head[6] = {'O', 'P', 'K', 0x00, 0x00, 0x00};
if (create_args != nullptr)
{
m_id = 0x40;
m_id |= (create_args->lookup_int('R')) ? 0x00 : 0x02;
m_id |= (create_args->lookup_int('P')) ? 0x04 : 0x00;
m_id |= (create_args->lookup_int('W')) ? 0x00 : 0x08;
m_id |= (create_args->lookup_int('B')) ? 0x00 : 0x10;
m_id |= (create_args->lookup_int('C')) ? 0x20 : 0x00;
m_size = create_args->lookup_int('S');
}
else
{
// 64k RAM datapack by default
m_id = 0x7c;
m_size = 0x08;
}
fwrite(opk_head, 6);
fwrite(&m_id, 1);
fwrite(&m_size, 1);
return image_init_result::PASS;
}
/*-------------------------------------------------
DEVICE_IMAGE_UNLOAD( datapack )
-------------------------------------------------*/
void datapack_device::call_unload()
{
m_id = 0;
m_size = 0;
m_counter = 0;
m_page = 0;
m_segment = 0;
m_control = 0;
m_data = 0;
}