mirror of
https://github.com/holub/mame
synced 2025-10-07 09:25:34 +03:00
Modernized decocass_tape device. (nw)
This commit is contained in:
parent
aa65080862
commit
1862219897
@ -932,7 +932,7 @@ READ8_MEMBER(decocass_state::decocass_e5xx_r)
|
|||||||
/* E5x2-E5x3 and mirrors */
|
/* E5x2-E5x3 and mirrors */
|
||||||
if (2 == (offset & E5XX_MASK))
|
if (2 == (offset & E5XX_MASK))
|
||||||
{
|
{
|
||||||
UINT8 bot_eot = (tape_get_status_bits(m_cassette) >> 5) & 1;
|
UINT8 bot_eot = (m_cassette->get_status_bits() >> 5) & 1;
|
||||||
|
|
||||||
data =
|
data =
|
||||||
(BIT(m_i8041_p1, 7) << 0) | /* D0 = P17 - REQ/ */
|
(BIT(m_i8041_p1, 7) << 0) | /* D0 = P17 - REQ/ */
|
||||||
@ -942,7 +942,7 @@ READ8_MEMBER(decocass_state::decocass_e5xx_r)
|
|||||||
((bot_eot) << 4) | /* D4 = BOT/EOT (direct from drive) */
|
((bot_eot) << 4) | /* D4 = BOT/EOT (direct from drive) */
|
||||||
(1 << 5) | /* D5 floating input */
|
(1 << 5) | /* D5 floating input */
|
||||||
(1 << 6) | /* D6 floating input */
|
(1 << 6) | /* D6 floating input */
|
||||||
(!tape_is_present(m_cassette) << 7); /* D7 = cassette present */
|
(!m_cassette->is_present() << 7); /* D7 = cassette present */
|
||||||
|
|
||||||
LOG(4,("%10s 6502-PC: %04x decocass_e5xx_r(%02x): $%02x <- STATUS (%s%s%s%s%s%s%s%s)\n",
|
LOG(4,("%10s 6502-PC: %04x decocass_e5xx_r(%02x): $%02x <- STATUS (%s%s%s%s%s%s%s%s)\n",
|
||||||
space.machine().time().as_string(6),
|
space.machine().time().as_string(6),
|
||||||
@ -1468,7 +1468,7 @@ WRITE8_MEMBER(decocass_state::i8041_p1_w)
|
|||||||
newspeed = (data & 0x04) ? -1 : -7;
|
newspeed = (data & 0x04) ? -1 : -7;
|
||||||
else if ((data & 0x30) == 0x10)
|
else if ((data & 0x30) == 0x10)
|
||||||
newspeed = (data & 0x04) ? 1 : 7;
|
newspeed = (data & 0x04) ? 1 : 7;
|
||||||
tape_change_speed(m_cassette, newspeed);
|
m_cassette->change_speed(newspeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_i8041_p1 = data;
|
m_i8041_p1 = data;
|
||||||
@ -1522,7 +1522,7 @@ READ8_MEMBER(decocass_state::i8041_p2_r)
|
|||||||
{
|
{
|
||||||
UINT8 data;
|
UINT8 data;
|
||||||
|
|
||||||
data = (m_i8041_p2 & ~0xe0) | tape_get_status_bits(m_cassette);
|
data = (m_i8041_p2 & ~0xe0) | m_cassette->get_status_bits();
|
||||||
|
|
||||||
if (data != m_i8041_p2_read_latch)
|
if (data != m_i8041_p2_read_latch)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include "cpu/m6502/m6502.h"
|
#include "cpu/m6502/m6502.h"
|
||||||
#include "cpu/mcs48/mcs48.h"
|
#include "cpu/mcs48/mcs48.h"
|
||||||
#include "machine/decocass_tape.h"
|
#include "machine/decocass_tape.h"
|
||||||
#include "devlegcy.h"
|
|
||||||
|
|
||||||
#define LOG_CASSETTE_STATE 0
|
#define LOG_CASSETTE_STATE 0
|
||||||
|
|
||||||
@ -16,57 +15,6 @@
|
|||||||
CASSETTE DEVICE INTERFACE
|
CASSETTE DEVICE INTERFACE
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
/* regions within the virtual tape */
|
|
||||||
enum tape_region
|
|
||||||
{
|
|
||||||
REGION_LEADER, /* in clear leader section */
|
|
||||||
REGION_LEADER_GAP, /* in gap between leader and BOT */
|
|
||||||
REGION_BOT, /* in BOT hole */
|
|
||||||
REGION_BOT_GAP, /* in gap between BOT hole and data */
|
|
||||||
REGION_DATA_BLOCK_0, /* in data block 0 */
|
|
||||||
REGION_DATA_BLOCK_255 = REGION_DATA_BLOCK_0 + 255,
|
|
||||||
REGION_EOT_GAP, /* in gap between data and EOT hole */
|
|
||||||
REGION_EOT, /* in EOT hole */
|
|
||||||
REGION_TRAILER_GAP, /* in gap between trailer and EOT */
|
|
||||||
REGION_TRAILER /* in clear trailer section */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* bytes within a data block on a virtual tape */
|
|
||||||
enum tape_byte
|
|
||||||
{
|
|
||||||
BYTE_PRE_GAP_0, /* 34 bytes of gap, clock held to 0, no data */
|
|
||||||
BYTE_PRE_GAP_33 = BYTE_PRE_GAP_0 + 33,
|
|
||||||
BYTE_LEADIN, /* 1 leadin byte, clocked value 0x00 */
|
|
||||||
BYTE_HEADER, /* 1 header byte, clocked value 0xAA */
|
|
||||||
BYTE_DATA_0, /* 256 bytes of data, clocked */
|
|
||||||
BYTE_DATA_255 = BYTE_DATA_0 + 255,
|
|
||||||
BYTE_CRC16_MSB, /* 2 bytes of CRC, clocked MSB first, then LSB */
|
|
||||||
BYTE_CRC16_LSB,
|
|
||||||
BYTE_TRAILER, /* 1 trailer byte, clocked value 0xAA */
|
|
||||||
BYTE_LEADOUT, /* 1 leadout byte, clocked value 0x00 */
|
|
||||||
BYTE_LONGCLOCK, /* 1 longclock byte, clock held to 1, no data */
|
|
||||||
BYTE_POSTGAP_0, /* 34 bytes of gap, no clock, no data */
|
|
||||||
BYTE_POSTGAP_33 = BYTE_POSTGAP_0 + 33,
|
|
||||||
BYTE_BLOCK_TOTAL /* total number of bytes in block */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* state of the tape */
|
|
||||||
struct tape_state
|
|
||||||
{
|
|
||||||
running_machine * machine; /* pointer back to the machine */
|
|
||||||
emu_timer * timer; /* timer for running the tape */
|
|
||||||
INT8 speed; /* speed: <-1=fast rewind, -1=reverse, 0=stopped, 1=normal, >1=fast forward */
|
|
||||||
tape_region region; /* current region */
|
|
||||||
tape_byte bytenum; /* byte number within a datablock */
|
|
||||||
UINT8 bitnum; /* bit number within a byte */
|
|
||||||
UINT32 clockpos; /* the current clock position of the tape */
|
|
||||||
UINT32 numclocks; /* total number of clocks on the entire tape */
|
|
||||||
UINT16 crc16[256]; /* CRC16 for each block */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* number of tape clock pulses per second */
|
/* number of tape clock pulses per second */
|
||||||
#define TAPE_CLOCKRATE 4800
|
#define TAPE_CLOCKRATE 4800
|
||||||
#define TAPE_CLOCKS_PER_BIT 2
|
#define TAPE_CLOCKS_PER_BIT 2
|
||||||
@ -104,20 +52,88 @@ struct tape_state
|
|||||||
#define REGION_BOT_GAP_LEN_CLOCKS TAPE_MSEC_TO_CLOCKS(300) /* 300ms */
|
#define REGION_BOT_GAP_LEN_CLOCKS TAPE_MSEC_TO_CLOCKS(300) /* 300ms */
|
||||||
#define REGION_BOT_GAP_END_CLOCK (REGION_BOT_GAP_START_CLOCK+REGION_BOT_GAP_LEN_CLOCKS)
|
#define REGION_BOT_GAP_END_CLOCK (REGION_BOT_GAP_START_CLOCK+REGION_BOT_GAP_LEN_CLOCKS)
|
||||||
|
|
||||||
|
static UINT16 tape_crc16_byte(UINT16 crc, UINT8 data);
|
||||||
|
|
||||||
/*-------------------------------------------------
|
const device_type DECOCASS_TAPE = &device_creator<decocass_tape_device>;
|
||||||
get_safe_token - makes sure that the passed
|
|
||||||
in device is, in fact, an IDE controller
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
INLINE tape_state *get_safe_token(device_t *device)
|
decocass_tape_device::decocass_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||||
|
: device_t(mconfig, DECOCASS_TAPE, "DECO Cassette Tape", tag, owner, clock, "decocass_tape", __FILE__),
|
||||||
|
m_tape_timer(NULL),
|
||||||
|
m_speed(0),
|
||||||
|
m_bitnum(0),
|
||||||
|
m_clockpos(0),
|
||||||
|
m_numclocks(0)
|
||||||
{
|
{
|
||||||
assert(device != NULL);
|
for (int i = 0; i < 256; i++)
|
||||||
assert(device->type() == DECOCASS_TAPE);
|
m_crc16[i] = 0;
|
||||||
|
|
||||||
return (tape_state *)downcast<decocass_tape_device *>(device)->token();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// device_config_complete - perform any
|
||||||
|
// operations now that the configuration is
|
||||||
|
// complete
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void decocass_tape_device::device_config_complete()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// device_start - device-specific startup
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void decocass_tape_device::device_start()
|
||||||
|
{
|
||||||
|
int curblock, offs, numblocks;
|
||||||
|
|
||||||
|
/* fetch the data pointer */
|
||||||
|
m_tape_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(decocass_tape_device::tape_clock_callback), this));
|
||||||
|
if (region() == NULL)
|
||||||
|
return;
|
||||||
|
UINT8 *regionbase = *region();
|
||||||
|
|
||||||
|
/* scan for the first non-empty block in the image */
|
||||||
|
for (offs = region()->bytes() - 1; offs >= 0; offs--)
|
||||||
|
if (regionbase[offs] != 0)
|
||||||
|
break;
|
||||||
|
numblocks = ((offs | 0xff) + 1) / 256;
|
||||||
|
assert(numblocks < ARRAY_LENGTH(m_crc16));
|
||||||
|
|
||||||
|
/* compute the total length */
|
||||||
|
m_numclocks = REGION_BOT_GAP_END_CLOCK + numblocks * BYTE_BLOCK_TOTAL * 16 + REGION_BOT_GAP_END_CLOCK;
|
||||||
|
|
||||||
|
/* compute CRCs for each block */
|
||||||
|
for (curblock = 0; curblock < numblocks; curblock++)
|
||||||
|
{
|
||||||
|
UINT16 crc = 0;
|
||||||
|
int testval;
|
||||||
|
|
||||||
|
/* first CRC the 256 bytes of data */
|
||||||
|
for (offs = 256 * curblock; offs < 256 * curblock + 256; offs++)
|
||||||
|
crc = tape_crc16_byte(crc, regionbase[offs]);
|
||||||
|
|
||||||
|
/* then find a pair of bytes that will bring the CRC to 0 (any better way than brute force?) */
|
||||||
|
for (testval = 0; testval < 0x10000; testval++)
|
||||||
|
if (tape_crc16_byte(tape_crc16_byte(crc, testval >> 8), testval) == 0)
|
||||||
|
break;
|
||||||
|
m_crc16[curblock] = testval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* register states */
|
||||||
|
save_item(NAME(m_speed));
|
||||||
|
save_item(NAME(m_bitnum));
|
||||||
|
save_item(NAME(m_clockpos));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// device_reset - device-specific reset
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void decocass_tape_device::device_reset()
|
||||||
|
{
|
||||||
|
/* turn the tape off */
|
||||||
|
change_speed(0);
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
tape_crc16_byte - accumulate 8 bits worth of
|
tape_crc16_byte - accumulate 8 bits worth of
|
||||||
@ -139,33 +155,32 @@ static UINT16 tape_crc16_byte(UINT16 crc, UINT8 data)
|
|||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
/*-------------------------------------------------
|
||||||
tape_describe_state - create a string that
|
tape_describe_state - create a string that
|
||||||
describes the state of the tape
|
describes the state of the tape
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
static const char *tape_describe_state(tape_state *tape)
|
const char *decocass_tape_device::describe_state()
|
||||||
{
|
{
|
||||||
static char buffer[40];
|
static char buffer[40];
|
||||||
char temprname[40];
|
char temprname[40];
|
||||||
const char *rname = temprname;
|
const char *rname = temprname;
|
||||||
|
|
||||||
if (tape->region == REGION_LEADER)
|
if (m_region == REGION_LEADER)
|
||||||
rname = "LEAD";
|
rname = "LEAD";
|
||||||
else if (tape->region == REGION_LEADER_GAP)
|
else if (m_region == REGION_LEADER_GAP)
|
||||||
rname = "LGAP";
|
rname = "LGAP";
|
||||||
else if (tape->region == REGION_BOT)
|
else if (m_region == REGION_BOT)
|
||||||
rname = "BOT ";
|
rname = "BOT ";
|
||||||
else if (tape->region == REGION_BOT_GAP)
|
else if (m_region == REGION_BOT_GAP)
|
||||||
rname = "BGAP";
|
rname = "BGAP";
|
||||||
else if (tape->region == REGION_TRAILER)
|
else if (m_region == REGION_TRAILER)
|
||||||
rname = "TRLR";
|
rname = "TRLR";
|
||||||
else if (tape->region == REGION_TRAILER_GAP)
|
else if (m_region == REGION_TRAILER_GAP)
|
||||||
rname = "TGAP";
|
rname = "TGAP";
|
||||||
else if (tape->region == REGION_EOT)
|
else if (m_region == REGION_EOT)
|
||||||
rname = "EOT ";
|
rname = "EOT ";
|
||||||
else if (tape->region == REGION_EOT_GAP)
|
else if (m_region == REGION_EOT_GAP)
|
||||||
rname = "EGAP";
|
rname = "EGAP";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -173,39 +188,39 @@ static const char *tape_describe_state(tape_state *tape)
|
|||||||
const char *bname = tempbname;
|
const char *bname = tempbname;
|
||||||
int clk;
|
int clk;
|
||||||
|
|
||||||
if (tape->bytenum <= BYTE_PRE_GAP_33)
|
if (m_bytenum <= BYTE_PRE_GAP_33)
|
||||||
sprintf(tempbname, "PR%02d", tape->bytenum - BYTE_PRE_GAP_0);
|
sprintf(tempbname, "PR%02d", m_bytenum - BYTE_PRE_GAP_0);
|
||||||
else if (tape->bytenum == BYTE_LEADIN)
|
else if (m_bytenum == BYTE_LEADIN)
|
||||||
bname = "LDIN";
|
bname = "LDIN";
|
||||||
else if (tape->bytenum == BYTE_HEADER)
|
else if (m_bytenum == BYTE_HEADER)
|
||||||
bname = "HEAD";
|
bname = "HEAD";
|
||||||
else if (tape->bytenum <= BYTE_DATA_255)
|
else if (m_bytenum <= BYTE_DATA_255)
|
||||||
sprintf(tempbname, "BY%02X", tape->bytenum - BYTE_DATA_0);
|
sprintf(tempbname, "BY%02X", m_bytenum - BYTE_DATA_0);
|
||||||
else if (tape->bytenum == BYTE_CRC16_MSB)
|
else if (m_bytenum == BYTE_CRC16_MSB)
|
||||||
bname = "CRCM";
|
bname = "CRCM";
|
||||||
else if (tape->bytenum == BYTE_CRC16_LSB)
|
else if (m_bytenum == BYTE_CRC16_LSB)
|
||||||
bname = "CRCL";
|
bname = "CRCL";
|
||||||
else if (tape->bytenum == BYTE_TRAILER)
|
else if (m_bytenum == BYTE_TRAILER)
|
||||||
bname = "TRLR";
|
bname = "TRLR";
|
||||||
else if (tape->bytenum == BYTE_LEADOUT)
|
else if (m_bytenum == BYTE_LEADOUT)
|
||||||
bname = "LOUT";
|
bname = "LOUT";
|
||||||
else if (tape->bytenum == BYTE_LONGCLOCK)
|
else if (m_bytenum == BYTE_LONGCLOCK)
|
||||||
bname = "LONG";
|
bname = "LONG";
|
||||||
else
|
else
|
||||||
sprintf(tempbname, "PO%02d", tape->bytenum - BYTE_POSTGAP_0);
|
sprintf(tempbname, "PO%02d", m_bytenum - BYTE_POSTGAP_0);
|
||||||
|
|
||||||
/* in the main data area, the clock alternates at the clock rate */
|
/* in the main data area, the clock alternates at the clock rate */
|
||||||
if (tape->bytenum >= BYTE_LEADIN && tape->bytenum <= BYTE_LEADOUT)
|
if (m_bytenum >= BYTE_LEADIN && m_bytenum <= BYTE_LEADOUT)
|
||||||
clk = ((UINT32)(tape->clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0 : 1;
|
clk = ((UINT32)(m_clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0 : 1;
|
||||||
else if (tape->bytenum == BYTE_LONGCLOCK)
|
else if (m_bytenum == BYTE_LONGCLOCK)
|
||||||
clk = 1;
|
clk = 1;
|
||||||
else
|
else
|
||||||
clk = 0;
|
clk = 0;
|
||||||
|
|
||||||
sprintf(temprname, "BL%02X.%4s.%d.%d", tape->region - REGION_DATA_BLOCK_0, bname, tape->bitnum, clk);
|
sprintf(temprname, "BL%02X.%4s.%d.%d", m_region - REGION_DATA_BLOCK_0, bname, m_bitnum, clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(buffer, "{%9d=%s}", tape->clockpos, rname);
|
sprintf(buffer, "{%9d=%s}", m_clockpos, rname);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,57 +230,54 @@ static const char *tape_describe_state(tape_state *tape)
|
|||||||
to increment/decrement the tape location
|
to increment/decrement the tape location
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
static TIMER_CALLBACK( tape_clock_callback )
|
TIMER_CALLBACK_MEMBER( decocass_tape_device::tape_clock_callback )
|
||||||
{
|
{
|
||||||
device_t *device = (device_t *)ptr;
|
|
||||||
tape_state *tape = get_safe_token(device);
|
|
||||||
|
|
||||||
/* advance by one clock in the desired direction */
|
/* advance by one clock in the desired direction */
|
||||||
if (tape->speed < 0 && tape->clockpos > 0)
|
if (m_speed < 0 && m_clockpos > 0)
|
||||||
tape->clockpos--;
|
m_clockpos--;
|
||||||
else if (tape->speed > 0 && tape->clockpos < tape->numclocks)
|
else if (m_speed > 0 && m_clockpos < m_numclocks)
|
||||||
tape->clockpos++;
|
m_clockpos++;
|
||||||
|
|
||||||
/* look for states before the start of data */
|
/* look for states before the start of data */
|
||||||
if (tape->clockpos < REGION_LEADER_END_CLOCK)
|
if (m_clockpos < REGION_LEADER_END_CLOCK)
|
||||||
tape->region = REGION_LEADER;
|
m_region = REGION_LEADER;
|
||||||
else if (tape->clockpos < REGION_LEADER_GAP_END_CLOCK)
|
else if (m_clockpos < REGION_LEADER_GAP_END_CLOCK)
|
||||||
tape->region = REGION_LEADER_GAP;
|
m_region = REGION_LEADER_GAP;
|
||||||
else if (tape->clockpos < REGION_BOT_END_CLOCK)
|
else if (m_clockpos < REGION_BOT_END_CLOCK)
|
||||||
tape->region = REGION_BOT;
|
m_region = REGION_BOT;
|
||||||
else if (tape->clockpos < REGION_BOT_GAP_END_CLOCK)
|
else if (m_clockpos < REGION_BOT_GAP_END_CLOCK)
|
||||||
tape->region = REGION_BOT_GAP;
|
m_region = REGION_BOT_GAP;
|
||||||
|
|
||||||
/* look for states after the end of data */
|
/* look for states after the end of data */
|
||||||
else if (tape->clockpos >= tape->numclocks - REGION_LEADER_END_CLOCK)
|
else if (m_clockpos >= m_numclocks - REGION_LEADER_END_CLOCK)
|
||||||
tape->region = REGION_TRAILER;
|
m_region = REGION_TRAILER;
|
||||||
else if (tape->clockpos >= tape->numclocks - REGION_LEADER_GAP_END_CLOCK)
|
else if (m_clockpos >= m_numclocks - REGION_LEADER_GAP_END_CLOCK)
|
||||||
tape->region = REGION_TRAILER_GAP;
|
m_region = REGION_TRAILER_GAP;
|
||||||
else if (tape->clockpos >= tape->numclocks - REGION_BOT_END_CLOCK)
|
else if (m_clockpos >= m_numclocks - REGION_BOT_END_CLOCK)
|
||||||
tape->region = REGION_EOT;
|
m_region = REGION_EOT;
|
||||||
else if (tape->clockpos >= tape->numclocks - REGION_BOT_GAP_END_CLOCK)
|
else if (m_clockpos >= m_numclocks - REGION_BOT_GAP_END_CLOCK)
|
||||||
tape->region = REGION_EOT_GAP;
|
m_region = REGION_EOT_GAP;
|
||||||
|
|
||||||
/* everything else is data */
|
/* everything else is data */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UINT32 dataclock = tape->clockpos - REGION_BOT_GAP_END_CLOCK;
|
UINT32 dataclock = m_clockpos - REGION_BOT_GAP_END_CLOCK;
|
||||||
|
|
||||||
/* compute the block number */
|
/* compute the block number */
|
||||||
tape->region = (tape_region)(REGION_DATA_BLOCK_0 + dataclock / (TAPE_CLOCKS_PER_BYTE * BYTE_BLOCK_TOTAL));
|
m_region = (tape_region)(REGION_DATA_BLOCK_0 + dataclock / (TAPE_CLOCKS_PER_BYTE * BYTE_BLOCK_TOTAL));
|
||||||
dataclock -= (tape->region - REGION_DATA_BLOCK_0) * TAPE_CLOCKS_PER_BYTE * BYTE_BLOCK_TOTAL;
|
dataclock -= (m_region - REGION_DATA_BLOCK_0) * TAPE_CLOCKS_PER_BYTE * BYTE_BLOCK_TOTAL;
|
||||||
|
|
||||||
/* compute the byte within the block */
|
/* compute the byte within the block */
|
||||||
tape->bytenum = (tape_byte)(dataclock / TAPE_CLOCKS_PER_BYTE);
|
m_bytenum = (tape_byte)(dataclock / TAPE_CLOCKS_PER_BYTE);
|
||||||
dataclock -= tape->bytenum * TAPE_CLOCKS_PER_BYTE;
|
dataclock -= m_bytenum * TAPE_CLOCKS_PER_BYTE;
|
||||||
|
|
||||||
/* compute the bit within the byte */
|
/* compute the bit within the byte */
|
||||||
tape->bitnum = dataclock / TAPE_CLOCKS_PER_BIT;
|
m_bitnum = dataclock / TAPE_CLOCKS_PER_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* log */
|
/* log */
|
||||||
if (LOG_CASSETTE_STATE)
|
if (LOG_CASSETTE_STATE)
|
||||||
tape_describe_state(tape);
|
describe_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -274,28 +286,27 @@ static TIMER_CALLBACK( tape_clock_callback )
|
|||||||
bits from the tape
|
bits from the tape
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
UINT8 tape_get_status_bits(device_t *device)
|
UINT8 decocass_tape_device::get_status_bits()
|
||||||
{
|
{
|
||||||
tape_state *tape = get_safe_token(device);
|
|
||||||
UINT8 tape_bits = 0;
|
UINT8 tape_bits = 0;
|
||||||
|
|
||||||
/* bit 0x20 is the BOT/EOT signal, which is also set in the leader/trailer area */
|
/* bit 0x20 is the BOT/EOT signal, which is also set in the leader/trailer area */
|
||||||
if (tape->region == REGION_LEADER || tape->region == REGION_BOT || tape->region == REGION_EOT || tape->region == REGION_TRAILER)
|
if (m_region == REGION_LEADER || m_region == REGION_BOT || m_region == REGION_EOT || m_region == REGION_TRAILER)
|
||||||
tape_bits |= 0x20;
|
tape_bits |= 0x20;
|
||||||
|
|
||||||
/* bit 0x40 is the clock, which is only valid in some areas of the data block */
|
/* bit 0x40 is the clock, which is only valid in some areas of the data block */
|
||||||
/* bit 0x80 is the data, which is only valid in some areas of the data block */
|
/* bit 0x80 is the data, which is only valid in some areas of the data block */
|
||||||
if (tape->region >= REGION_DATA_BLOCK_0 && tape->region <= REGION_DATA_BLOCK_255)
|
if (m_region >= REGION_DATA_BLOCK_0 && m_region <= REGION_DATA_BLOCK_255)
|
||||||
{
|
{
|
||||||
int blocknum = tape->region - REGION_DATA_BLOCK_0;
|
int blocknum = m_region - REGION_DATA_BLOCK_0;
|
||||||
UINT8 byteval = 0x00;
|
UINT8 byteval = 0x00;
|
||||||
|
|
||||||
/* in the main data area, the clock alternates at the clock rate */
|
/* in the main data area, the clock alternates at the clock rate */
|
||||||
if (tape->bytenum >= BYTE_LEADIN && tape->bytenum <= BYTE_LEADOUT)
|
if (m_bytenum >= BYTE_LEADIN && m_bytenum <= BYTE_LEADOUT)
|
||||||
tape_bits |= ((UINT32)(tape->clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0x00 : 0x40;
|
tape_bits |= ((UINT32)(m_clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0x00 : 0x40;
|
||||||
|
|
||||||
/* in the longclock area, the clock holds high */
|
/* in the longclock area, the clock holds high */
|
||||||
else if (tape->bytenum == BYTE_LONGCLOCK)
|
else if (m_bytenum == BYTE_LONGCLOCK)
|
||||||
tape_bits |= 0x40;
|
tape_bits |= 0x40;
|
||||||
|
|
||||||
/* everywhere else, the clock holds to 0 */
|
/* everywhere else, the clock holds to 0 */
|
||||||
@ -303,23 +314,23 @@ UINT8 tape_get_status_bits(device_t *device)
|
|||||||
;
|
;
|
||||||
|
|
||||||
/* lead-in and lead-out bytes are 0xAA */
|
/* lead-in and lead-out bytes are 0xAA */
|
||||||
if (tape->bytenum == BYTE_HEADER || tape->bytenum == BYTE_TRAILER)
|
if (m_bytenum == BYTE_HEADER || m_bytenum == BYTE_TRAILER)
|
||||||
byteval = 0xaa;
|
byteval = 0xaa;
|
||||||
|
|
||||||
/* data block bytes are data */
|
/* data block bytes are data */
|
||||||
else if (tape->bytenum >= BYTE_DATA_0 && tape->bytenum <= BYTE_DATA_255)
|
else if (m_bytenum >= BYTE_DATA_0 && m_bytenum <= BYTE_DATA_255)
|
||||||
byteval = static_cast<UINT8 *>(*device->region())[blocknum * 256 + (tape->bytenum - BYTE_DATA_0)];
|
byteval = static_cast<UINT8 *>(*region())[blocknum * 256 + (m_bytenum - BYTE_DATA_0)];
|
||||||
|
|
||||||
/* CRC MSB */
|
/* CRC MSB */
|
||||||
else if (tape->bytenum == BYTE_CRC16_MSB)
|
else if (m_bytenum == BYTE_CRC16_MSB)
|
||||||
byteval = tape->crc16[blocknum] >> 8;
|
byteval = m_crc16[blocknum] >> 8;
|
||||||
|
|
||||||
/* CRC LSB */
|
/* CRC LSB */
|
||||||
else if (tape->bytenum == BYTE_CRC16_LSB)
|
else if (m_bytenum == BYTE_CRC16_LSB)
|
||||||
byteval = tape->crc16[blocknum];
|
byteval = m_crc16[blocknum];
|
||||||
|
|
||||||
/* select the appropriate bit from the byte and move to the upper bit */
|
/* select the appropriate bit from the byte and move to the upper bit */
|
||||||
if ((byteval >> tape->bitnum) & 1)
|
if ((byteval >> m_bitnum) & 1)
|
||||||
tape_bits |= 0x80;
|
tape_bits |= 0x80;
|
||||||
}
|
}
|
||||||
return tape_bits;
|
return tape_bits;
|
||||||
@ -331,9 +342,9 @@ UINT8 tape_get_status_bits(device_t *device)
|
|||||||
present
|
present
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
UINT8 tape_is_present(device_t *device)
|
UINT8 decocass_tape_device::is_present()
|
||||||
{
|
{
|
||||||
return device->region() != NULL;
|
return region() != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -342,14 +353,13 @@ UINT8 tape_is_present(device_t *device)
|
|||||||
playback
|
playback
|
||||||
-------------------------------------------------*/
|
-------------------------------------------------*/
|
||||||
|
|
||||||
void tape_change_speed(device_t *device, INT8 newspeed)
|
void decocass_tape_device::change_speed(INT8 newspeed)
|
||||||
{
|
{
|
||||||
tape_state *tape = get_safe_token(device);
|
|
||||||
attotime newperiod;
|
attotime newperiod;
|
||||||
INT8 absnewspeed;
|
INT8 absnewspeed;
|
||||||
|
|
||||||
/* do nothing if speed has not changed */
|
/* do nothing if speed has not changed */
|
||||||
if (tape->speed == newspeed)
|
if (m_speed == newspeed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* compute how fast to run the tape timer */
|
/* compute how fast to run the tape timer */
|
||||||
@ -360,107 +370,6 @@ void tape_change_speed(device_t *device, INT8 newspeed)
|
|||||||
newperiod = attotime::from_hz(TAPE_CLOCKRATE * absnewspeed);
|
newperiod = attotime::from_hz(TAPE_CLOCKRATE * absnewspeed);
|
||||||
|
|
||||||
/* set the new speed */
|
/* set the new speed */
|
||||||
tape->timer->adjust(newperiod, 0, newperiod);
|
m_tape_timer->adjust(newperiod, 0, newperiod);
|
||||||
tape->speed = newspeed;
|
m_speed = newspeed;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
device start callback
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static DEVICE_START( decocass_tape )
|
|
||||||
{
|
|
||||||
tape_state *tape = get_safe_token(device);
|
|
||||||
int curblock, offs, numblocks;
|
|
||||||
|
|
||||||
/* validate some basic stuff */
|
|
||||||
assert(device != NULL);
|
|
||||||
assert(device->static_config() == NULL);
|
|
||||||
|
|
||||||
/* fetch the data pointer */
|
|
||||||
tape->timer = device->machine().scheduler().timer_alloc(FUNC(tape_clock_callback), (void *)device);
|
|
||||||
if (device->region() == NULL)
|
|
||||||
return;
|
|
||||||
UINT8 *regionbase = *device->region();
|
|
||||||
|
|
||||||
/* scan for the first non-empty block in the image */
|
|
||||||
for (offs = device->region()->bytes() - 1; offs >= 0; offs--)
|
|
||||||
if (regionbase[offs] != 0)
|
|
||||||
break;
|
|
||||||
numblocks = ((offs | 0xff) + 1) / 256;
|
|
||||||
assert(numblocks < ARRAY_LENGTH(tape->crc16));
|
|
||||||
|
|
||||||
/* compute the total length */
|
|
||||||
tape->numclocks = REGION_BOT_GAP_END_CLOCK + numblocks * BYTE_BLOCK_TOTAL * 16 + REGION_BOT_GAP_END_CLOCK;
|
|
||||||
|
|
||||||
/* compute CRCs for each block */
|
|
||||||
for (curblock = 0; curblock < numblocks; curblock++)
|
|
||||||
{
|
|
||||||
UINT16 crc = 0;
|
|
||||||
int testval;
|
|
||||||
|
|
||||||
/* first CRC the 256 bytes of data */
|
|
||||||
for (offs = 256 * curblock; offs < 256 * curblock + 256; offs++)
|
|
||||||
crc = tape_crc16_byte(crc, regionbase[offs]);
|
|
||||||
|
|
||||||
/* then find a pair of bytes that will bring the CRC to 0 (any better way than brute force?) */
|
|
||||||
for (testval = 0; testval < 0x10000; testval++)
|
|
||||||
if (tape_crc16_byte(tape_crc16_byte(crc, testval >> 8), testval) == 0)
|
|
||||||
break;
|
|
||||||
tape->crc16[curblock] = testval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* register states */
|
|
||||||
device->save_item(NAME(tape->speed));
|
|
||||||
device->save_item(NAME(tape->bitnum));
|
|
||||||
device->save_item(NAME(tape->clockpos));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------
|
|
||||||
device reset callback
|
|
||||||
-------------------------------------------------*/
|
|
||||||
|
|
||||||
static DEVICE_RESET( decocass_tape )
|
|
||||||
{
|
|
||||||
/* turn the tape off */
|
|
||||||
tape_change_speed(device, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const device_type DECOCASS_TAPE = &device_creator<decocass_tape_device>;
|
|
||||||
|
|
||||||
decocass_tape_device::decocass_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
|
||||||
: device_t(mconfig, DECOCASS_TAPE, "DECO Cassette Tape", tag, owner, clock, "decocass_tape", __FILE__)
|
|
||||||
{
|
|
||||||
m_token = global_alloc_clear(tape_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// device_config_complete - perform any
|
|
||||||
// operations now that the configuration is
|
|
||||||
// complete
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
void decocass_tape_device::device_config_complete()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// device_start - device-specific startup
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
void decocass_tape_device::device_start()
|
|
||||||
{
|
|
||||||
DEVICE_START_NAME( decocass_tape )(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// device_reset - device-specific reset
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
void decocass_tape_device::device_reset()
|
|
||||||
{
|
|
||||||
DEVICE_RESET_NAME( decocass_tape )(this);
|
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,70 @@ class decocass_tape_device : public device_t
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
decocass_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
decocass_tape_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||||
~decocass_tape_device() { global_free(m_token); }
|
~decocass_tape_device() {}
|
||||||
|
|
||||||
// access to legacy token
|
UINT8 get_status_bits();
|
||||||
void *token() const { assert(m_token != NULL); return m_token; }
|
UINT8 is_present();
|
||||||
|
void change_speed(INT8 newspeed);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// device-level overrides
|
// device-level overrides
|
||||||
virtual void device_config_complete();
|
virtual void device_config_complete();
|
||||||
virtual void device_start();
|
virtual void device_start();
|
||||||
virtual void device_reset();
|
virtual void device_reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/* regions within the virtual tape */
|
||||||
|
enum tape_region
|
||||||
|
{
|
||||||
|
REGION_LEADER, /* in clear leader section */
|
||||||
|
REGION_LEADER_GAP, /* in gap between leader and BOT */
|
||||||
|
REGION_BOT, /* in BOT hole */
|
||||||
|
REGION_BOT_GAP, /* in gap between BOT hole and data */
|
||||||
|
REGION_DATA_BLOCK_0, /* in data block 0 */
|
||||||
|
REGION_DATA_BLOCK_255 = REGION_DATA_BLOCK_0 + 255,
|
||||||
|
REGION_EOT_GAP, /* in gap between data and EOT hole */
|
||||||
|
REGION_EOT, /* in EOT hole */
|
||||||
|
REGION_TRAILER_GAP, /* in gap between trailer and EOT */
|
||||||
|
REGION_TRAILER /* in clear trailer section */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* bytes within a data block on a virtual tape */
|
||||||
|
enum tape_byte
|
||||||
|
{
|
||||||
|
BYTE_PRE_GAP_0, /* 34 bytes of gap, clock held to 0, no data */
|
||||||
|
BYTE_PRE_GAP_33 = BYTE_PRE_GAP_0 + 33,
|
||||||
|
BYTE_LEADIN, /* 1 leadin byte, clocked value 0x00 */
|
||||||
|
BYTE_HEADER, /* 1 header byte, clocked value 0xAA */
|
||||||
|
BYTE_DATA_0, /* 256 bytes of data, clocked */
|
||||||
|
BYTE_DATA_255 = BYTE_DATA_0 + 255,
|
||||||
|
BYTE_CRC16_MSB, /* 2 bytes of CRC, clocked MSB first, then LSB */
|
||||||
|
BYTE_CRC16_LSB,
|
||||||
|
BYTE_TRAILER, /* 1 trailer byte, clocked value 0xAA */
|
||||||
|
BYTE_LEADOUT, /* 1 leadout byte, clocked value 0x00 */
|
||||||
|
BYTE_LONGCLOCK, /* 1 longclock byte, clock held to 1, no data */
|
||||||
|
BYTE_POSTGAP_0, /* 34 bytes of gap, no clock, no data */
|
||||||
|
BYTE_POSTGAP_33 = BYTE_POSTGAP_0 + 33,
|
||||||
|
BYTE_BLOCK_TOTAL /* total number of bytes in block */
|
||||||
|
};
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
void *m_token;
|
emu_timer * m_tape_timer; /* timer for running the tape */
|
||||||
|
INT8 m_speed; /* speed: <-1=fast rewind, -1=reverse, 0=stopped, 1=normal, >1=fast forward */
|
||||||
|
tape_region m_region; /* current region */
|
||||||
|
tape_byte m_bytenum; /* byte number within a datablock */
|
||||||
|
UINT8 m_bitnum; /* bit number within a byte */
|
||||||
|
UINT32 m_clockpos; /* the current clock position of the tape */
|
||||||
|
UINT32 m_numclocks; /* total number of clocks on the entire tape */
|
||||||
|
UINT16 m_crc16[256]; /* CRC16 for each block */
|
||||||
|
|
||||||
|
const char *describe_state();
|
||||||
|
TIMER_CALLBACK_MEMBER( tape_clock_callback );
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const device_type DECOCASS_TAPE;
|
extern const device_type DECOCASS_TAPE;
|
||||||
|
|
||||||
UINT8 tape_get_status_bits(device_t *device);
|
|
||||||
UINT8 tape_is_present(device_t *device);
|
|
||||||
void tape_change_speed(device_t *device, INT8 newspeed);
|
|
||||||
|
|
||||||
|
|
||||||
#define MCFG_DECOCASS_TAPE_ADD(_tag) \
|
#define MCFG_DECOCASS_TAPE_ADD(_tag) \
|
||||||
MCFG_DEVICE_ADD(_tag, DECOCASS_TAPE, 0)
|
MCFG_DEVICE_ADD(_tag, DECOCASS_TAPE, 0)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user