Modernized decocass_tape device. (nw)

This commit is contained in:
Ivan Vangelista 2013-08-06 15:23:27 +00:00
parent aa65080862
commit 1862219897
3 changed files with 208 additions and 256 deletions

View File

@ -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)
{ {

View File

@ -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);
} }

View File

@ -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)