mirror of
https://github.com/holub/mame
synced 2025-07-09 03:38:23 +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 */
|
||||
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 =
|
||||
(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) */
|
||||
(1 << 5) | /* D5 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",
|
||||
space.machine().time().as_string(6),
|
||||
@ -1468,7 +1468,7 @@ WRITE8_MEMBER(decocass_state::i8041_p1_w)
|
||||
newspeed = (data & 0x04) ? -1 : -7;
|
||||
else if ((data & 0x30) == 0x10)
|
||||
newspeed = (data & 0x04) ? 1 : 7;
|
||||
tape_change_speed(m_cassette, newspeed);
|
||||
m_cassette->change_speed(newspeed);
|
||||
}
|
||||
|
||||
m_i8041_p1 = data;
|
||||
@ -1522,7 +1522,7 @@ READ8_MEMBER(decocass_state::i8041_p2_r)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "cpu/m6502/m6502.h"
|
||||
#include "cpu/mcs48/mcs48.h"
|
||||
#include "machine/decocass_tape.h"
|
||||
#include "devlegcy.h"
|
||||
|
||||
#define LOG_CASSETTE_STATE 0
|
||||
|
||||
@ -16,57 +15,6 @@
|
||||
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 */
|
||||
#define TAPE_CLOCKRATE 4800
|
||||
#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_END_CLOCK (REGION_BOT_GAP_START_CLOCK+REGION_BOT_GAP_LEN_CLOCKS)
|
||||
|
||||
static UINT16 tape_crc16_byte(UINT16 crc, UINT8 data);
|
||||
|
||||
/*-------------------------------------------------
|
||||
get_safe_token - makes sure that the passed
|
||||
in device is, in fact, an IDE controller
|
||||
-------------------------------------------------*/
|
||||
const device_type DECOCASS_TAPE = &device_creator<decocass_tape_device>;
|
||||
|
||||
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);
|
||||
assert(device->type() == DECOCASS_TAPE);
|
||||
|
||||
return (tape_state *)downcast<decocass_tape_device *>(device)->token();
|
||||
for (int i = 0; i < 256; i++)
|
||||
m_crc16[i] = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// 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
|
||||
@ -139,33 +155,32 @@ static UINT16 tape_crc16_byte(UINT16 crc, UINT8 data)
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
tape_describe_state - create a string that
|
||||
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];
|
||||
char temprname[40];
|
||||
const char *rname = temprname;
|
||||
|
||||
if (tape->region == REGION_LEADER)
|
||||
if (m_region == REGION_LEADER)
|
||||
rname = "LEAD";
|
||||
else if (tape->region == REGION_LEADER_GAP)
|
||||
else if (m_region == REGION_LEADER_GAP)
|
||||
rname = "LGAP";
|
||||
else if (tape->region == REGION_BOT)
|
||||
else if (m_region == REGION_BOT)
|
||||
rname = "BOT ";
|
||||
else if (tape->region == REGION_BOT_GAP)
|
||||
else if (m_region == REGION_BOT_GAP)
|
||||
rname = "BGAP";
|
||||
else if (tape->region == REGION_TRAILER)
|
||||
else if (m_region == REGION_TRAILER)
|
||||
rname = "TRLR";
|
||||
else if (tape->region == REGION_TRAILER_GAP)
|
||||
else if (m_region == REGION_TRAILER_GAP)
|
||||
rname = "TGAP";
|
||||
else if (tape->region == REGION_EOT)
|
||||
else if (m_region == REGION_EOT)
|
||||
rname = "EOT ";
|
||||
else if (tape->region == REGION_EOT_GAP)
|
||||
else if (m_region == REGION_EOT_GAP)
|
||||
rname = "EGAP";
|
||||
else
|
||||
{
|
||||
@ -173,39 +188,39 @@ static const char *tape_describe_state(tape_state *tape)
|
||||
const char *bname = tempbname;
|
||||
int clk;
|
||||
|
||||
if (tape->bytenum <= BYTE_PRE_GAP_33)
|
||||
sprintf(tempbname, "PR%02d", tape->bytenum - BYTE_PRE_GAP_0);
|
||||
else if (tape->bytenum == BYTE_LEADIN)
|
||||
if (m_bytenum <= BYTE_PRE_GAP_33)
|
||||
sprintf(tempbname, "PR%02d", m_bytenum - BYTE_PRE_GAP_0);
|
||||
else if (m_bytenum == BYTE_LEADIN)
|
||||
bname = "LDIN";
|
||||
else if (tape->bytenum == BYTE_HEADER)
|
||||
else if (m_bytenum == BYTE_HEADER)
|
||||
bname = "HEAD";
|
||||
else if (tape->bytenum <= BYTE_DATA_255)
|
||||
sprintf(tempbname, "BY%02X", tape->bytenum - BYTE_DATA_0);
|
||||
else if (tape->bytenum == BYTE_CRC16_MSB)
|
||||
else if (m_bytenum <= BYTE_DATA_255)
|
||||
sprintf(tempbname, "BY%02X", m_bytenum - BYTE_DATA_0);
|
||||
else if (m_bytenum == BYTE_CRC16_MSB)
|
||||
bname = "CRCM";
|
||||
else if (tape->bytenum == BYTE_CRC16_LSB)
|
||||
else if (m_bytenum == BYTE_CRC16_LSB)
|
||||
bname = "CRCL";
|
||||
else if (tape->bytenum == BYTE_TRAILER)
|
||||
else if (m_bytenum == BYTE_TRAILER)
|
||||
bname = "TRLR";
|
||||
else if (tape->bytenum == BYTE_LEADOUT)
|
||||
else if (m_bytenum == BYTE_LEADOUT)
|
||||
bname = "LOUT";
|
||||
else if (tape->bytenum == BYTE_LONGCLOCK)
|
||||
else if (m_bytenum == BYTE_LONGCLOCK)
|
||||
bname = "LONG";
|
||||
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 */
|
||||
if (tape->bytenum >= BYTE_LEADIN && tape->bytenum <= BYTE_LEADOUT)
|
||||
clk = ((UINT32)(tape->clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0 : 1;
|
||||
else if (tape->bytenum == BYTE_LONGCLOCK)
|
||||
if (m_bytenum >= BYTE_LEADIN && m_bytenum <= BYTE_LEADOUT)
|
||||
clk = ((UINT32)(m_clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0 : 1;
|
||||
else if (m_bytenum == BYTE_LONGCLOCK)
|
||||
clk = 1;
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
@ -215,57 +230,54 @@ static const char *tape_describe_state(tape_state *tape)
|
||||
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 */
|
||||
if (tape->speed < 0 && tape->clockpos > 0)
|
||||
tape->clockpos--;
|
||||
else if (tape->speed > 0 && tape->clockpos < tape->numclocks)
|
||||
tape->clockpos++;
|
||||
if (m_speed < 0 && m_clockpos > 0)
|
||||
m_clockpos--;
|
||||
else if (m_speed > 0 && m_clockpos < m_numclocks)
|
||||
m_clockpos++;
|
||||
|
||||
/* look for states before the start of data */
|
||||
if (tape->clockpos < REGION_LEADER_END_CLOCK)
|
||||
tape->region = REGION_LEADER;
|
||||
else if (tape->clockpos < REGION_LEADER_GAP_END_CLOCK)
|
||||
tape->region = REGION_LEADER_GAP;
|
||||
else if (tape->clockpos < REGION_BOT_END_CLOCK)
|
||||
tape->region = REGION_BOT;
|
||||
else if (tape->clockpos < REGION_BOT_GAP_END_CLOCK)
|
||||
tape->region = REGION_BOT_GAP;
|
||||
if (m_clockpos < REGION_LEADER_END_CLOCK)
|
||||
m_region = REGION_LEADER;
|
||||
else if (m_clockpos < REGION_LEADER_GAP_END_CLOCK)
|
||||
m_region = REGION_LEADER_GAP;
|
||||
else if (m_clockpos < REGION_BOT_END_CLOCK)
|
||||
m_region = REGION_BOT;
|
||||
else if (m_clockpos < REGION_BOT_GAP_END_CLOCK)
|
||||
m_region = REGION_BOT_GAP;
|
||||
|
||||
/* look for states after the end of data */
|
||||
else if (tape->clockpos >= tape->numclocks - REGION_LEADER_END_CLOCK)
|
||||
tape->region = REGION_TRAILER;
|
||||
else if (tape->clockpos >= tape->numclocks - REGION_LEADER_GAP_END_CLOCK)
|
||||
tape->region = REGION_TRAILER_GAP;
|
||||
else if (tape->clockpos >= tape->numclocks - REGION_BOT_END_CLOCK)
|
||||
tape->region = REGION_EOT;
|
||||
else if (tape->clockpos >= tape->numclocks - REGION_BOT_GAP_END_CLOCK)
|
||||
tape->region = REGION_EOT_GAP;
|
||||
else if (m_clockpos >= m_numclocks - REGION_LEADER_END_CLOCK)
|
||||
m_region = REGION_TRAILER;
|
||||
else if (m_clockpos >= m_numclocks - REGION_LEADER_GAP_END_CLOCK)
|
||||
m_region = REGION_TRAILER_GAP;
|
||||
else if (m_clockpos >= m_numclocks - REGION_BOT_END_CLOCK)
|
||||
m_region = REGION_EOT;
|
||||
else if (m_clockpos >= m_numclocks - REGION_BOT_GAP_END_CLOCK)
|
||||
m_region = REGION_EOT_GAP;
|
||||
|
||||
/* everything else is data */
|
||||
else
|
||||
{
|
||||
UINT32 dataclock = tape->clockpos - REGION_BOT_GAP_END_CLOCK;
|
||||
UINT32 dataclock = m_clockpos - REGION_BOT_GAP_END_CLOCK;
|
||||
|
||||
/* compute the block number */
|
||||
tape->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;
|
||||
m_region = (tape_region)(REGION_DATA_BLOCK_0 + dataclock / (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 */
|
||||
tape->bytenum = (tape_byte)(dataclock / TAPE_CLOCKS_PER_BYTE);
|
||||
dataclock -= tape->bytenum * TAPE_CLOCKS_PER_BYTE;
|
||||
m_bytenum = (tape_byte)(dataclock / TAPE_CLOCKS_PER_BYTE);
|
||||
dataclock -= m_bytenum * TAPE_CLOCKS_PER_BYTE;
|
||||
|
||||
/* compute the bit within the byte */
|
||||
tape->bitnum = dataclock / TAPE_CLOCKS_PER_BIT;
|
||||
m_bitnum = dataclock / TAPE_CLOCKS_PER_BIT;
|
||||
}
|
||||
|
||||
/* log */
|
||||
if (LOG_CASSETTE_STATE)
|
||||
tape_describe_state(tape);
|
||||
describe_state();
|
||||
}
|
||||
|
||||
|
||||
@ -274,28 +286,27 @@ static TIMER_CALLBACK( tape_clock_callback )
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
|
||||
/* in the main data area, the clock alternates at the clock rate */
|
||||
if (tape->bytenum >= BYTE_LEADIN && tape->bytenum <= BYTE_LEADOUT)
|
||||
tape_bits |= ((UINT32)(tape->clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0x00 : 0x40;
|
||||
if (m_bytenum >= BYTE_LEADIN && m_bytenum <= BYTE_LEADOUT)
|
||||
tape_bits |= ((UINT32)(m_clockpos - REGION_BOT_GAP_END_CLOCK) & 1) ? 0x00 : 0x40;
|
||||
|
||||
/* in the longclock area, the clock holds high */
|
||||
else if (tape->bytenum == BYTE_LONGCLOCK)
|
||||
else if (m_bytenum == BYTE_LONGCLOCK)
|
||||
tape_bits |= 0x40;
|
||||
|
||||
/* 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 */
|
||||
if (tape->bytenum == BYTE_HEADER || tape->bytenum == BYTE_TRAILER)
|
||||
if (m_bytenum == BYTE_HEADER || m_bytenum == BYTE_TRAILER)
|
||||
byteval = 0xaa;
|
||||
|
||||
/* data block bytes are data */
|
||||
else if (tape->bytenum >= BYTE_DATA_0 && tape->bytenum <= BYTE_DATA_255)
|
||||
byteval = static_cast<UINT8 *>(*device->region())[blocknum * 256 + (tape->bytenum - BYTE_DATA_0)];
|
||||
else if (m_bytenum >= BYTE_DATA_0 && m_bytenum <= BYTE_DATA_255)
|
||||
byteval = static_cast<UINT8 *>(*region())[blocknum * 256 + (m_bytenum - BYTE_DATA_0)];
|
||||
|
||||
/* CRC MSB */
|
||||
else if (tape->bytenum == BYTE_CRC16_MSB)
|
||||
byteval = tape->crc16[blocknum] >> 8;
|
||||
else if (m_bytenum == BYTE_CRC16_MSB)
|
||||
byteval = m_crc16[blocknum] >> 8;
|
||||
|
||||
/* CRC LSB */
|
||||
else if (tape->bytenum == BYTE_CRC16_LSB)
|
||||
byteval = tape->crc16[blocknum];
|
||||
else if (m_bytenum == BYTE_CRC16_LSB)
|
||||
byteval = m_crc16[blocknum];
|
||||
|
||||
/* 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;
|
||||
}
|
||||
return tape_bits;
|
||||
@ -331,9 +342,9 @@ UINT8 tape_get_status_bits(device_t *device)
|
||||
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
|
||||
-------------------------------------------------*/
|
||||
|
||||
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;
|
||||
INT8 absnewspeed;
|
||||
|
||||
/* do nothing if speed has not changed */
|
||||
if (tape->speed == newspeed)
|
||||
if (m_speed == newspeed)
|
||||
return;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* set the new speed */
|
||||
tape->timer->adjust(newperiod, 0, newperiod);
|
||||
tape->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);
|
||||
m_tape_timer->adjust(newperiod, 0, newperiod);
|
||||
m_speed = newspeed;
|
||||
}
|
||||
|
@ -5,27 +5,70 @@ class decocass_tape_device : public device_t
|
||||
{
|
||||
public:
|
||||
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
|
||||
void *token() const { assert(m_token != NULL); return m_token; }
|
||||
UINT8 get_status_bits();
|
||||
UINT8 is_present();
|
||||
void change_speed(INT8 newspeed);
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_config_complete();
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
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) \
|
||||
MCFG_DEVICE_ADD(_tag, DECOCASS_TAPE, 0)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user