// license:BSD-3-Clause
// copyright-holders:R. Belmont, Ville Linde
/*
machine/model3.c: functions emulating various aspects of the Model 3 hardware
*/
#include "emu.h"
#include "includes/model3.h"
/******************************************************************/
/* Real3D TAP Port */
/******************************************************************/
/*
* TAP Finite State Machine
*
* Y are states and X are outgoing paths. Constructed from information on page
* 167 of the 3D-RAM manual.
*/
#define NEXT(new_state) fsm[m_tap_state][new_state]
static const int32_t fsm[][2] = {
{ 1, 0 }, // 0 Test-Logic/Reset
{ 1, 2 }, // 1 Run-Test/Idle
{ 3, 9 }, // 2 Select-DR-Scan
{ 4, 5 }, // 3 Capture-DR
{ 4, 5 }, // 4 Shift-DR
{ 6, 8 }, // 5 Exit1-DR
{ 6, 7 }, // 6 Pause-DR
{ 4, 8 }, // 7 Exit2-DR
{ 1, 2 }, // 8 Update-DR
{ 10, 0 }, // 9 Select-IR-Scan
{ 11, 12 }, // 10 Capture-IR
{ 11, 12 }, // 11 Shift-IR
{ 13, 15 }, // 12 Exit1-IR
{ 13, 14 }, // 13 Pause-IR
{ 11, 15 }, // 14 Exit2-IR
{ 1, 2 } // 15 Update-IR
};
/*
* insert_bit():
*
* Inserts a bit into an arbitrarily long bit field. Bit 0 is assumed to be
* the MSB of the first byte in the buffer.
*/
static void insert_bit(uint8_t *buf, int32_t bit_num, int32_t bit)
{
int32_t bit_in_byte;
bit_in_byte = 7 - (bit_num & 7);
buf[bit_num / 8] &= ~(1 << bit_in_byte);
buf[bit_num / 8] |= (bit << bit_in_byte);
}
/*
* insert_id():
*
* Inserts a 32-bit ID code into the ID bit field.
*/
void model3_state::insert_id(uint32_t id, int32_t start_bit)
{
for (int i = 31; i >= 0; i--)
insert_bit(m_id_data, start_bit++, (id >> i) & 1);
}
/*
* shift():
*
* Shifts the data buffer right (towards LSB at byte 0) by 1 bit. The size of
* the number of bits must be specified. The bit shifted out of the LSB is
* returned.
*/
static int shift(uint8_t *data, int32_t num_bits)
{
int32_t i;
int shift_out, shift_in;
/*
* This loop takes care of all the fully-filled bytes
*/
shift_in = 0;
shift_out = 0;
for (i = 0; i < num_bits / 8; i++)
{
shift_out = data[i] & 1;
data[i] >>= 1;
data[i] |= (shift_in << 7);
shift_in = shift_out; // carry over to next element's MSB
}
/*
* Take care of the last partial byte (if there is one)
*/
if ((num_bits & 7) != 0)
{
shift_out = (data[i] >> (8 - (num_bits & 7))) & 1;
data[i] >>= 1;
data[i] |= (shift_in << 7);
}
return shift_out;
}
/*
* int tap_read(void);
*
* Reads TDO.
*
* Returns:
* TDO.
*/
int model3_state::tap_read()
{
return m_tdo;
}
/*
* void tap_write(int tck, int tms, int tdi, int trst);
*
* Writes to the TAP. State changes only occur on the rising edge of the clock
* (tck = 1.)
*
* Parameters:
* tck = Clock.
* tms = Test mode select.
* tdi = Serial data input. Must be 0 or 1 only!
* trst = Reset.
*/
void model3_state::tap_write(int tck, int tms, int tdi, int trst)
{
if (!tck)
return;
m_tap_state = NEXT(tms);
switch (m_tap_state)
{
case 3: // Capture-DR
//printf("capture dr (IR = %08X%08X\n", (uint32_t)(m_ir >> 32),(uint32_t)(m_ir));
if (m_ir == 0x000023fffffffffeU)
{
for (auto & elem : m_id_data)
{
elem = 0;
}
m_id_size = 41;
uint64_t res = 0x0040000000;
int start_bit = 0;
for (int i = 41; i >= 0; i--)
insert_bit(m_id_data, start_bit++, ((uint64_t)(1 << i) & res) ? 1 : 0);
}
else if (m_ir == 0x00000c631f8c7ffeU)
{
tap_set_asic_ids();
}
break;
case 4: // Shift-DR
m_tdo = shift(m_id_data, m_id_size);
break;
case 10: // Capture-IR
/*
* Load lower 2 bits with 01 as per IEEE 1149.1-1990
*/
m_ir = 1;
break;
case 11: // Shift-IR
/*
* Shift IR towards output and load in new data from TDI
*/
m_tdo = m_ir & 1; // shift LSB to output
m_ir >>= 1;
m_ir |= ((uint64_t) tdi << 45);
break;
case 15: // Update-IR
/*
* Latch IR (technically, this should occur on the falling edge of
* TCK)
*/
m_ir &= 0x3fffffffffffU;
break;
default:
break;
}
}
void model3_state::tap_set_asic_ids()
{
/*
* Read ASIC IDs.
*
* The ID Sequence is:
* - Jupiter
* - Mercury
* - Venus
* - Earth
* - Mars
* - Mars (again)
*
* Note that different Model 3 steps have different chip
* revisions, hence the different IDs returned below.
*
* On Step 1.5 and 1.0, instruction 0x0C631F8C7FFE is used to retrieve
* the ID codes but Step 2.0 is a little weirder. It seems to use this
* and either the state of the TAP after reset or other instructions
* to read the IDs as well. This can be emulated in one of 2 ways:
* Ignore the instruction and always load up the data or load the
* data on TAP reset and when the instruction is issued.
*/
for (auto & elem : m_id_data)
{
elem = 0;
}
if (m_m3_step == 0x10)
{
insert_id(0x116C7057, 1 + 0 * 32);
insert_id(0x216C3057, 1 + 1 * 32);
insert_id(0x116C4057, 1 + 2 * 32);
insert_id(0x216C5057, 1 + 3 * 32);
insert_id(0x116C6057, 1 + 4 * 32 + 1);
insert_id(0x116C6057, 1 + 5 * 32 + 1);
}
else if (m_m3_step == 0x15)
{
insert_id(0x316C7057, 1 + 0 * 32);
insert_id(0x316C3057, 1 + 1 * 32);
insert_id(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057
insert_id(0x316C5057, 1 + 3 * 32);
insert_id(0x216C6057, 1 + 4 * 32 + 1);
insert_id(0x216C6057, 1 + 5 * 32 + 1);
}
else if (m_m3_step >= 0x20)
{
insert_id(0x416C7057, 1 + 0 * 32);
insert_id(0x416C3057, 1 + 1 * 32);
insert_id(0x316C4057, 1 + 2 * 32);
insert_id(0x416C5057, 1 + 3 * 32);
insert_id(0x316C6057, 1 + 4 * 32 + 1);
insert_id(0x316C6057, 1 + 5 * 32 + 1);
}
m_id_size = 197; // 197 bits
}
/*
* void tap_reset(void);
*
* Resets the TAP (simulating a power up or SCAN_RST signal.)
*/
void model3_state::tap_reset()
{
m_tap_state = 0; // test-logic/reset
tap_set_asic_ids();
}
/*****************************************************************************/
/* Epson RTC-72421 */
READ32_MEMBER(model3_state::rtc72421_r)
{
int reg = offset;
uint32_t data;
data = m_rtc->read(space, reg) << 24;
data |= 0x30000; /* these bits are set to pass the battery voltage test */
return data;
}
WRITE32_MEMBER(model3_state::rtc72421_w)
{
m_rtc->write(space, offset, data >> 24);
}