diff options
Diffstat (limited to 'src/mame/machine/decocass.c')
-rw-r--r-- | src/mame/machine/decocass.c | 2159 |
1 files changed, 2159 insertions, 0 deletions
diff --git a/src/mame/machine/decocass.c b/src/mame/machine/decocass.c new file mode 100644 index 00000000000..4af788d0b08 --- /dev/null +++ b/src/mame/machine/decocass.c @@ -0,0 +1,2159 @@ +/*********************************************************************** + + DECO Cassette System machine + + ***********************************************************************/ + +#include "driver.h" +#include "cpu/m6502/m6502.h" +#include "cpu/i8x41/i8x41.h" +#include "machine/decocass.h" + +/* tape direction, speed and timing (used also in video/decocass.c) */ +INT32 tape_dir; +INT32 tape_speed; +attotime tape_time0; +emu_timer *tape_timer; + +static INT32 firsttime = 1; +static INT32 tape_present; +static INT32 tape_blocks; +static INT32 tape_length; +static INT32 tape_bot_eot; +static UINT8 crc16_lsb; +static UINT8 crc16_msb; + +/* pre-calculated crc16 of the tape blocks */ +static UINT8 tape_crc16_lsb[256]; +static UINT8 tape_crc16_msb[256]; + +static read8_handler decocass_dongle_r; +static write8_handler decocass_dongle_w; + +static UINT8 decocass_reset; +static UINT8 i8041_p1; +static UINT8 i8041_p2; + +/* dongle type #1: jumpers C and D assignments */ +#define MAKE_MAP(m0,m1,m2,m3,m4,m5,m6,m7) \ + ((UINT32)(m0)) | \ + ((UINT32)(m1) << 3) | \ + ((UINT32)(m2) << 6) | \ + ((UINT32)(m3) << 9) | \ + ((UINT32)(m4) << 12) | \ + ((UINT32)(m5) << 15) | \ + ((UINT32)(m6) << 18) | \ + ((UINT32)(m7) << 21) + +#define MAP0(m) ((m)&7) +#define MAP1(m) (((m)>>3)&7) +#define MAP2(m) (((m)>>6)&7) +#define MAP3(m) (((m)>>9)&7) +#define MAP4(m) (((m)>>12)&7) +#define MAP5(m) (((m)>>15)&7) +#define MAP6(m) (((m)>>18)&7) +#define MAP7(m) (((m)>>21)&7) + +static UINT32 type1_inmap; +static UINT32 type1_outmap; + +static INT32 de0091_enable; /* DE-0091xx daughter board enable */ + +/* dongle type #2: status of the latches */ +static INT32 type2_d2_latch; /* latched 8041-STATUS D2 value */ +static INT32 type2_xx_latch; /* latched value (D7-4 == 0xc0) ? 1 : 0 */ +static INT32 type2_promaddr; /* latched PROM address A0-A7 */ + +/* dongle type #3: status and patches */ +static INT32 type3_ctrs; /* 12 bit counter stage */ +static INT32 type3_d0_latch; /* latched 8041-D0 value */ +static INT32 type3_pal_19; /* latched 1 for PAL input pin-19 */ +static INT32 type3_swap; +enum { + TYPE3_SWAP_01, + TYPE3_SWAP_12, + TYPE3_SWAP_13, + TYPE3_SWAP_24, + TYPE3_SWAP_25, + TYPE3_SWAP_34_0, + TYPE3_SWAP_34_7, + TYPE3_SWAP_23_56, + TYPE3_SWAP_56, + TYPE3_SWAP_67 +}; + +/* dongle type #4: status */ +static INT32 type4_ctrs; /* latched PROM address (E5x0 LSB, E5x1 MSB) */ +static INT32 type4_latch; /* latched enable PROM (1100xxxx written to E5x1) */ + +/* dongle type #5: status */ +static INT32 type5_latch; /* latched enable PROM (1100xxxx written to E5x1) */ + +/* four inputs from the quadrature decoder (H1, V1, H2, V2) */ +static UINT8 decocass_quadrature_decoder[4]; + +/* sound latches, ACK status bits and NMI timer */ +static UINT8 decocass_sound_ack; +static emu_timer *decocass_sound_timer; + +WRITE8_HANDLER( decocass_coin_counter_w ) +{ +} + +WRITE8_HANDLER( decocass_sound_command_w ) +{ + LOG(2,("CPU #%d sound command -> $%02x\n", cpu_getactivecpu(), data)); + soundlatch_w(0,data); + decocass_sound_ack |= 0x80; + /* remove snd cpu data ack bit. i don't see it in the schems, but... */ + decocass_sound_ack &= ~0x40; + cpunum_set_input_line(1, M6502_IRQ_LINE, ASSERT_LINE); +} + +READ8_HANDLER( decocass_sound_data_r ) +{ + UINT8 data = soundlatch2_r(0); + LOG(2,("CPU #%d sound data <- $%02x\n", cpu_getactivecpu(), data)); + return data; +} + +READ8_HANDLER( decocass_sound_ack_r ) +{ + UINT8 data = decocass_sound_ack; /* D6+D7 */ + LOG(4,("CPU #%d sound ack <- $%02x\n", cpu_getactivecpu(), data)); + return data; +} + +WRITE8_HANDLER( decocass_sound_data_w ) +{ + LOG(2,("CPU #%d sound data -> $%02x\n", cpu_getactivecpu(), data)); + soundlatch2_w(0, data); + decocass_sound_ack |= 0x40; +} + +READ8_HANDLER( decocass_sound_command_r ) +{ + UINT8 data = soundlatch_r(0); + LOG(4,("CPU #%d sound command <- $%02x\n", cpu_getactivecpu(), data)); + cpunum_set_input_line(1, M6502_IRQ_LINE, CLEAR_LINE); + decocass_sound_ack &= ~0x80; + return data; +} + +static TIMER_CALLBACK( decocass_sound_nmi_pulse ) +{ + cpunum_set_input_line(1, INPUT_LINE_NMI, PULSE_LINE); +} + +WRITE8_HANDLER( decocass_sound_nmi_enable_w ) +{ + LOG(2,("CPU #%d sound NMI enb -> $%02x\n", cpu_getactivecpu(), data)); + timer_adjust(decocass_sound_timer, ATTOTIME_IN_HZ(256 * 57 / 8 / 2), 0, ATTOTIME_IN_HZ(256 * 57 / 8 / 2)); +} + +READ8_HANDLER( decocass_sound_nmi_enable_r ) +{ + UINT8 data = 0xff; + LOG(2,("CPU #%d sound NMI enb <- $%02x\n", cpu_getactivecpu(), data)); + timer_adjust(decocass_sound_timer, ATTOTIME_IN_HZ(256 * 57 / 8 / 2), 0, ATTOTIME_IN_HZ(256 * 57 / 8 / 2)); + return data; +} + +READ8_HANDLER( decocass_sound_data_ack_reset_r ) +{ + UINT8 data = 0xff; + LOG(2,("CPU #%d sound ack rst <- $%02x\n", cpu_getactivecpu(), data)); + decocass_sound_ack &= ~0x40; + return data; +} + +WRITE8_HANDLER( decocass_sound_data_ack_reset_w ) +{ + LOG(2,("CPU #%d sound ack rst -> $%02x\n", cpu_getactivecpu(), data)); + decocass_sound_ack &= ~0x40; +} + +WRITE8_HANDLER( decocass_nmi_reset_w ) +{ + cpunum_set_input_line(0, INPUT_LINE_NMI, CLEAR_LINE ); +} + +WRITE8_HANDLER( decocass_quadrature_decoder_reset_w ) +{ + /* just latch the analog controls here */ + decocass_quadrature_decoder[0] = input_port_3_r(0); + decocass_quadrature_decoder[1] = input_port_4_r(0); + decocass_quadrature_decoder[2] = input_port_5_r(0); + decocass_quadrature_decoder[3] = input_port_6_r(0); +} + +WRITE8_HANDLER( decocass_adc_w ) +{ +} + +/* + * E6x0 inputs + * E6x1 inputs + * E6x2 coin inp + * E6x3 quadrature decoder read + * E6x4 "" + * E6x5 "" + * E6x6 "" + * E6x7 a/d converter read + */ +READ8_HANDLER( decocass_input_r ) +{ + UINT8 data = 0xff; + switch (offset & 7) + { + case 0: case 1: case 2: + data = readinputport(offset & 7); + break; + case 3: case 4: case 5: case 6: + data = decocass_quadrature_decoder[(offset & 7) - 3]; + break; + default: + break; + } + + return data; +} + +/* + * D0 - REQ/ data request (8041 pin 34 port 1.7) + * D1 - FNO/ function number (8041 pin 21 port 2.0) + * D2 - EOT/ end-of-tape (8041 pin 22 port 2.1) + * D3 - ERR/ error condition (8041 pin 23 port 2.2) + * D4 - BOT-EOT from tape + * D5 - + * D6 - + * D7 - cassette present + */ +/* Note on a tapes leader-BOT-data-EOT-trailer format: + * A cassette has a transparent piece of tape on both ends, + * leader and trailer. And data tapes also have BOT and EOT + * holes, shortly before the the leader and trailer. + * The holes and clear tape are detected using a photo-resitor. + * When rewinding, the BOT/EOT signal will show a short + * pulse and if rewind continues a constant high signal later. + * The specs say the holes are "> 2ms" in length. + */ + +#define TAPE_CLOCKRATE 4800 /* clock pulses per second */ + +/* duration of the clear LEADER (and trailer) of the tape */ +#define TAPE_LEADER TAPE_CLOCKRATE /* 1s */ +/* duration of the GAP between leader and BOT/EOT */ +#define TAPE_GAP TAPE_CLOCKRATE*3/2 /* 1.5s */ +/* duration of BOT/EOT holes */ +#define TAPE_HOLE TAPE_CLOCKRATE/400 /* 0.0025s */ + +/* byte offset of the tape chunks (8 clocks per byte = 16 samples) */ +/* 300 ms GAP between BOT and first data block (doesn't work.. thus /2) */ +#define TAPE_PRE_GAP 34 +#define TAPE_LEADIN (TAPE_PRE_GAP + 1) +#define TAPE_HEADER (TAPE_LEADIN + 1) +#define TAPE_BLOCK (TAPE_HEADER + 256) +#define TAPE_CRC16_MSB (TAPE_BLOCK + 1) +#define TAPE_CRC16_LSB (TAPE_CRC16_MSB + 1) +#define TAPE_TRAILER (TAPE_CRC16_LSB + 1) +#define TAPE_LEADOUT (TAPE_TRAILER + 1) +#define TAPE_LONGCLOCK (TAPE_LEADOUT + 1) +#define TAPE_POST_GAP (TAPE_LONGCLOCK + 34) + +/* size of a tape chunk (block) including gaps */ +#define TAPE_CHUNK TAPE_POST_GAP + +#define E5XX_MASK 0x02 /* use 0x0e for old style board */ + +#define BIT0(x) ((x)&1) +#define BIT1(x) (((x)>>1)&1) +#define BIT2(x) (((x)>>2)&1) +#define BIT3(x) (((x)>>3)&1) +#define BIT4(x) (((x)>>4)&1) +#define BIT5(x) (((x)>>5)&1) +#define BIT6(x) (((x)>>6)&1) +#define BIT7(x) (((x)>>7)&1) + +WRITE8_HANDLER( decocass_reset_w ) +{ + LOG(1,("%9.7f 6502-PC: %04x decocass_reset_w(%02x): $%02x\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + decocass_reset = data; + + /* CPU #1 active hight reset */ + cpunum_set_input_line(1, INPUT_LINE_RESET, data & 0x01 ); + + /* on reset also remove the sound timer */ + if (data & 1) + timer_adjust(decocass_sound_timer, attotime_never, 0, attotime_never); + + /* 8041 active low reset */ + cpunum_set_input_line(2, INPUT_LINE_RESET, (data & 0x08) ^ 0x08 ); +} + +#ifdef MAME_DEBUG +static const char *dirnm(int speed) +{ + if (speed < -1) return "fast rewind"; + if (speed == -1) return "rewind"; + if (speed == 0) return "stop"; + if (speed == 1) return "forward"; + return "fast forward"; +} +#endif + +static void tape_crc16(UINT8 data) +{ + UINT8 c0, c1; + UINT8 old_lsb = crc16_lsb; + UINT8 old_msb = crc16_msb; + UINT8 feedback; + + feedback = ((data >> 7) ^ crc16_msb) & 1; + + /* rotate 16 bits */ + c0 = crc16_lsb & 1; + c1 = crc16_msb & 1; + crc16_msb = (crc16_msb >> 1) | (c0 << 7); + crc16_lsb = (crc16_lsb >> 1) | (c1 << 7); + + /* feedback into bit 7 */ + if (feedback) + crc16_lsb |= 0x80; + else + crc16_lsb &= ~0x80; + + /* feedback to bit 6 into bit 5 */ + if (((old_lsb >> 6) ^ feedback) & 1) + crc16_lsb |= 0x20; + else + crc16_lsb &= ~0x20; + + /* feedback to bit 1 into bit 0 */ + if (((old_msb >> 1) ^ feedback) & 1) + crc16_msb |= 0x01; + else + crc16_msb &= ~0x01; +} + + +attotime decocass_adjust_tape_time(attotime tape_time) +{ + attotime ret = tape_time; + + if (tape_timer) + { + attotime elapsed = timer_timeelapsed(tape_timer); + + if (tape_dir > 0) + { + ret = attotime_add(tape_time, elapsed); + + if (attotime_compare(ret, ATTOTIME_IN_MSEC(999900)) > 0) + ret = ATTOTIME_IN_MSEC(999900); + } + + if (tape_dir < 0) + { + if (attotime_compare(tape_time, elapsed) > 0) + ret = attotime_sub(tape_time, elapsed); + else + ret = attotime_zero; + } + } + + return ret; +} + + +static void tape_update(void) +{ + static int last_byte; + int offset, rclk, rdata, tape_bit, tape_byte, tape_block; + + attotime tape_time = decocass_adjust_tape_time(tape_time0); + + offset = (int)(attotime_to_double(attotime_mul(tape_time, TAPE_CLOCKRATE)) + 0.499995); + + /* reset RCLK and RDATA inputs */ + rclk = 0; + rdata = 0; + + if (offset < TAPE_LEADER) + { + if (offset < 0) + offset = 0; + /* LEADER area */ + if (0 == tape_bot_eot) + { + tape_bot_eot = 1; + set_led_status(1, 1); + LOG(5,("tape %5.4fs: %s found LEADER\n", attotime_to_double(tape_time), dirnm(tape_dir))); + } + } + else + if (offset < TAPE_LEADER + TAPE_GAP) + { + /* GAP between LEADER and BOT hole */ + if (1 == tape_bot_eot) + { + tape_bot_eot = 0; + set_led_status(1, 0); + LOG(5,("tape %5.4fs: %s between BOT + LEADER\n", attotime_to_double(tape_time), dirnm(tape_dir))); + } + } + else + if (offset < TAPE_LEADER + TAPE_GAP + TAPE_HOLE) + { + /* during BOT hole */ + if (0 == tape_bot_eot) + { + tape_bot_eot = 1; + set_led_status(1, 1); + LOG(5,("tape %5.4fs: %s found BOT\n", attotime_to_double(tape_time), dirnm(tape_dir))); + } + } + else + if (offset < tape_length - TAPE_LEADER - TAPE_GAP - TAPE_HOLE) + { + offset -= TAPE_LEADER + TAPE_GAP + TAPE_HOLE; + + /* data area */ + if (1 == tape_bot_eot) + { + tape_bot_eot = 0; + set_led_status(1, 0); + LOG(5,("tape %5.4fs: %s data area\n", attotime_to_double(tape_time), dirnm(tape_dir))); + } + rclk = (offset ^ 1) & 1; + tape_bit = (offset / 2) % 8; + tape_byte = (offset / 16) % TAPE_CHUNK; + tape_block = offset / 16 / TAPE_CHUNK; + + if (tape_byte < TAPE_PRE_GAP) + { + rclk = 0; + rdata = 0; + } + else + if (tape_byte < TAPE_LEADIN) + { + rdata = (0x00 >> tape_bit) & 1; + if (tape_byte != last_byte) + { + LOG(5,("tape %5.4fs: LEADIN $00\n", attotime_to_double(tape_time))); + set_led_status(2, 1); + } + } + else + if (tape_byte < TAPE_HEADER) + { + rdata = (0xaa >> tape_bit) & 1; + if (tape_byte != last_byte) + LOG(5,("tape %5.4fs: HEADER $aa\n", attotime_to_double(tape_time))); + } + else + if (tape_byte < TAPE_BLOCK) + { + UINT8 *ptr = memory_region(REGION_USER2) + tape_block * 256 + tape_byte - TAPE_HEADER; + rdata = (*ptr >> tape_bit) & 1; + if (tape_byte != last_byte) + LOG(4,("tape %5.4fs: DATA(%02x) $%02x\n", attotime_to_double(tape_time), tape_byte - TAPE_HEADER, *ptr)); + } + else + if (tape_byte < TAPE_CRC16_MSB) + { + rdata = (tape_crc16_msb[tape_block] >> tape_bit) & 1; + if (tape_byte != last_byte) + LOG(4,("tape %5.4fs: CRC16 MSB $%02x\n", attotime_to_double(tape_time), tape_crc16_msb[tape_block])); + } + else + if (tape_byte < TAPE_CRC16_LSB) + { + rdata = (tape_crc16_lsb[tape_block] >> tape_bit) & 1; + if (tape_byte != last_byte) + LOG(4,("tape %5.4fs: CRC16 LSB $%02x\n", attotime_to_double(tape_time), tape_crc16_lsb[tape_block])); + } + else + if (tape_byte < TAPE_TRAILER) + { + rdata = (0xaa >> tape_bit) & 1; + if (tape_byte != last_byte) + LOG(4,("tape %5.4fs: TRAILER $aa\n", attotime_to_double(tape_time))); + } + else + if (tape_byte < TAPE_LEADOUT) + { + rdata = (0x00 >> tape_bit) & 1; + if (tape_byte != last_byte) + LOG(4,("tape %5.4fs: LEADOUT $00\n", attotime_to_double(tape_time))); + } + else + if (tape_byte < TAPE_LONGCLOCK) + { + if (tape_byte != last_byte) + { + LOG(4,("tape %5.4fs: LONG CLOCK\n", attotime_to_double(tape_time))); + set_led_status(2, 0); + } + rclk = 1; + rdata = 0; + } + last_byte = tape_byte; + } + else + if (offset < tape_length - TAPE_LEADER - TAPE_GAP) + { + /* during EOT hole */ + if (0 == tape_bot_eot) + { + tape_bot_eot = 1; + set_led_status(1, 1); + LOG(5,("tape %5.4fs: %s found EOT\n", attotime_to_double(tape_time), dirnm(tape_dir))); + } + } + else + if (offset < tape_length - TAPE_LEADER) + { + /* GAP between EOT and trailer */ + if (1 == tape_bot_eot) + { + tape_bot_eot = 0; + set_led_status(1, 0); + LOG(5,("tape %5.4fs: %s EOT and TRAILER\n", attotime_to_double(tape_time), dirnm(tape_dir))); + } + } + else + { + /* TRAILER area */ + if (0 == tape_bot_eot) + { + tape_bot_eot = 1; + set_led_status(1, 1); + LOG(5,("tape %5.4fs: %s found TRAILER\n", attotime_to_double(tape_time), dirnm(tape_dir))); + } + offset = tape_length - 1; + } + + i8041_p2 = (i8041_p2 & ~0xe0) | (tape_bot_eot << 5) | (rclk << 6) | (rdata << 7); +} + +#ifdef MAME_DEBUG +static void decocass_fno(offs_t offset, UINT8 data) +{ + /* 8041ENA/ and is this a FNO write (function number)? */ + if (0 == (i8041_p2 & 0x01)) + { + switch (data) + { + case 0x25: logerror("8041 FNO 25: write_block\n"); break; + case 0x26: logerror("8041 FNO 26: rewind_block\n"); break; + case 0x27: logerror("8041 FNO 27: read_block_a\n"); break; + case 0x28: logerror("8041 FNO 28: read_block_b\n"); break; + case 0x29: logerror("8041 FNO 29: tape_rewind_fast\n"); break; + case 0x2a: logerror("8041 FNO 2a: tape_forward\n"); break; + case 0x2b: logerror("8041 FNO 2b: tape_rewind\n"); break; + case 0x2c: logerror("8041 FNO 2c: force_abort\n"); break; + case 0x2d: logerror("8041 FNO 2d: tape_erase\n"); break; + case 0x2e: logerror("8041 FNO 2e: search_tape_mark\n"); break; + case 0x2f: logerror("8041 FNO 2f: search_eot\n"); break; + case 0x30: logerror("8041 FNO 30: advance_block\n"); break; + case 0x31: logerror("8041 FNO 31: write_tape_mark\n"); break; + case 0x32: logerror("8041 FNO 32: reset_error\n"); break; + case 0x33: logerror("8041 FNO 33: flag_status_report\n"); break; + case 0x34: logerror("8041 FNO 34: report_status_to_main\n"); break; + default: logerror("8041 FNO %02x: invalid\n", data); + } + } +} +#endif + +/*************************************************************************** + * + * TYPE1 DONGLE (DE-0061) + * - Lock 'n Chase + * - Treasure Island + * - Super Astro Fighter + * - Lucky Poker + * - Terranian + * - Explorer + * - Pro Golf + * + * Latch bits 2 and 6, pass bit 3, invert bit 2. + * Lookup PROM DE-0061 using bits 0, 1, 4, 5, and 7 as the + * address bits; take PROM data 0-4 as data bits 0, 1, 4, 5, and 7. + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_type1_latch_26_pass_3_inv_2_r ) +{ + static UINT8 latch1; + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_STAT); + else + data = 0xff; + + data = (BIT0(data) << 0) | (BIT1(data) << 1) | 0x7c; + LOG(4,("%9.7f 6502-PC: %04x decocass_type1_latch_26_pass_3_inv_2_r(%02x): $%02x <- (%s %s)\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, + (data & 1) ? "OBF" : "-", + (data & 2) ? "IBF" : "-")); + } + else + { + offs_t promaddr; + UINT8 save; + UINT8 *prom = memory_region(REGION_USER1); + + if (firsttime) + { + LOG(3,("prom data:\n")); + for (promaddr = 0; promaddr < 32; promaddr++) + { + if (promaddr % 8 == 0) + LOG(3,(" %02x:", promaddr)); + LOG(3,(" %02x%s", prom[promaddr], (promaddr % 8) == 7 ? "\n" : "")); + } + firsttime = 0; + latch1 = 0; /* reset latch (??) */ + } + + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_DATA); + else + data = 0xff; + + save = data; /* save the unmodifed data for the latch */ + + promaddr = + (((data >> MAP0(type1_inmap)) & 1) << 0) | + (((data >> MAP1(type1_inmap)) & 1) << 1) | + (((data >> MAP4(type1_inmap)) & 1) << 2) | + (((data >> MAP5(type1_inmap)) & 1) << 3) | + (((data >> MAP7(type1_inmap)) & 1) << 4); + /* latch bits 2 and 6, pass bit 3, invert bit 2 */ + data = + (((prom[promaddr] >> 0) & 1) << MAP0(type1_outmap)) | + (((prom[promaddr] >> 1) & 1) << MAP1(type1_outmap)) | + ((1 - ((latch1 >> MAP2(type1_inmap)) & 1)) << MAP2(type1_outmap)) | + (((data >> MAP3(type1_inmap)) & 1) << MAP3(type1_outmap)) | + (((prom[promaddr] >> 2) & 1) << MAP4(type1_outmap)) | + (((prom[promaddr] >> 3) & 1) << MAP5(type1_outmap)) | + (((latch1 >> MAP6(type1_inmap)) & 1) << MAP6(type1_outmap)) | + (((prom[promaddr] >> 4) & 1) << MAP7(type1_outmap)); + + LOG(3,("%9.7f 6502-PC: %04x decocass_type1_latch_26_pass_3_inv_2_r(%02x): $%02x\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + + latch1 = save; /* latch the data for the next A0 == 0 read */ + } + return data; +} + + +/*************************************************************************** + * + * TYPE1 DONGLE (DE-0061) + * - Test Tape + * + * Pass bits 1, 3, and 6. Lookup PROM DE-0061 using bits 0, 2, 4, 5, and 7 + * as the address bits; take PROM data 0-4 as data bits 0, 2, 4, 5, and 7. + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_type1_pass_136_r ) +{ + static UINT8 latch1; + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_STAT); + else + data = 0xff; + + data = (BIT0(data) << 0) | (BIT1(data) << 1) | 0x7c; + LOG(4,("%9.7f 6502-PC: %04x decocass_type1_pass_136_r(%02x): $%02x <- (%s %s)\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, + (data & 1) ? "OBF" : "-", + (data & 2) ? "IBF" : "-")); + } + else + { + offs_t promaddr; + UINT8 save; + UINT8 *prom = memory_region(REGION_USER1); + + if (firsttime) + { + LOG(3,("prom data:\n")); + for (promaddr = 0; promaddr < 32; promaddr++) + { + if (promaddr % 8 == 0) + LOG(3,(" %02x:", promaddr)); + LOG(3,(" %02x%s", prom[promaddr], (promaddr % 8) == 7 ? "\n" : "")); + } + firsttime = 0; + latch1 = 0; /* reset latch (??) */ + } + + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_DATA); + else + data = 0xff; + + save = data; /* save the unmodifed data for the latch */ + + promaddr = + (((data >> MAP0(type1_inmap)) & 1) << 0) | + (((data >> MAP2(type1_inmap)) & 1) << 1) | + (((data >> MAP4(type1_inmap)) & 1) << 2) | + (((data >> MAP5(type1_inmap)) & 1) << 3) | + (((data >> MAP7(type1_inmap)) & 1) << 4); + /* latch bits 1 and 6, pass bit 3, invert bit 1 */ + data = + (((prom[promaddr] >> 0) & 1) << MAP0(type1_outmap)) | + (((data >> MAP1(type1_inmap)) & 1) << MAP1(type1_outmap)) | + (((prom[promaddr] >> 1) & 1) << MAP2(type1_outmap)) | + (((data >> MAP3(type1_inmap)) & 1) << MAP3(type1_outmap)) | + (((prom[promaddr] >> 2) & 1) << MAP4(type1_outmap)) | + (((prom[promaddr] >> 3) & 1) << MAP5(type1_outmap)) | + (((data >> MAP6(type1_inmap)) & 1) << MAP6(type1_outmap)) | + (((prom[promaddr] >> 4) & 1) << MAP7(type1_outmap)); + + LOG(3,("%9.7f 6502-PC: %04x decocass_type1_pass_136_r(%02x): $%02x\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + + latch1 = save; /* latch the data for the next A0 == 0 read */ + } + return data; +} + +/*************************************************************************** + * + * TYPE1 DONGLE (DE-0061) + * - Highway Chase + * + * Latch bits 2 and 7, pass bit 3, invert bit 2 to the output. + * Lookup PROM (Highway Chase) using data bits 0, 1, 4, 5, and 6 as the + * address bits. Take PROM data 0-4 as data bits 0, 1, 4, 5, and 6. + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_type1_latch_27_pass_3_inv_2_r ) +{ + static UINT8 latch1; + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_STAT); + else + data = 0xff; + + data = (BIT0(data) << 0) | (BIT1(data) << 1) | 0x7c; + LOG(4,("%9.7f 6502-PC: %04x decocass_type1_latch_27_pass_3_inv_2_r(%02x): $%02x <- (%s %s)\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, + (data & 1) ? "OBF" : "-", + (data & 2) ? "IBF" : "-")); + } + else + { + offs_t promaddr; + UINT8 save; + UINT8 *prom = memory_region(REGION_USER1); + + if (firsttime) + { + LOG(3,("prom data:\n")); + for (promaddr = 0; promaddr < 32; promaddr++) + { + if (promaddr % 8 == 0) + LOG(3,(" %02x:", promaddr)); + LOG(3,(" %02x%s", prom[promaddr], (promaddr % 8) == 7 ? "\n" : "")); + } + firsttime = 0; + latch1 = 0; /* reset latch (??) */ + } + + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_DATA); + else + data = 0xff; + + save = data; /* save the unmodifed data for the latch */ + + promaddr = + (((data >> MAP0(type1_inmap)) & 1) << 0) | + (((data >> MAP1(type1_inmap)) & 1) << 1) | + (((data >> MAP4(type1_inmap)) & 1) << 2) | + (((data >> MAP5(type1_inmap)) & 1) << 3) | + (((data >> MAP6(type1_inmap)) & 1) << 4); + /* latch bits 2 and 7, pass bit 3, invert bit 2 */ + data = + (((prom[promaddr] >> 0) & 1) << MAP0(type1_outmap)) | + (((prom[promaddr] >> 1) & 1) << MAP1(type1_outmap)) | + ((1 - ((latch1 >> MAP2(type1_inmap)) & 1)) << MAP2(type1_outmap)) | + (((data >> MAP3(type1_inmap)) & 1) << MAP3(type1_outmap)) | + (((prom[promaddr] >> 2) & 1) << MAP4(type1_outmap)) | + (((prom[promaddr] >> 3) & 1) << MAP5(type1_outmap)) | + (((prom[promaddr] >> 4) & 1) << MAP6(type1_outmap)) | + (((latch1 >> MAP7(type1_inmap)) & 1) << MAP7(type1_outmap)); + + LOG(3,("%9.7f 6502-PC: %04x decocass_type1_latch_27_pass_3_inv_2_r(%02x): $%02x\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + + latch1 = save; /* latch the data for the next A0 == 0 read */ + } + return data; +} + +/*************************************************************************** + * + * TYPE1 DONGLE (DE-0061) + * - Explorer + * + * Latch bits 2 and 6, pass bit 5, invert bit 2 to the output. + * Lookup PROM (Explorer) using bits 0, 1, 3, 4, and 7 as the + * address bits. Take PROM data 0-4 as data bits 0, 1, 3, 4, and 7. + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_type1_latch_26_pass_5_inv_2_r ) +{ + static UINT8 latch1; + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_STAT); + else + data = 0xff; + + data = (BIT0(data) << 0) | (BIT1(data) << 1) | 0x7c; + LOG(4,("%9.7f 6502-PC: %04x decocass_type1_latch_26_pass_5_inv_2_r(%02x): $%02x <- (%s %s)\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, + (data & 1) ? "OBF" : "-", + (data & 2) ? "IBF" : "-")); + } + else + { + offs_t promaddr; + UINT8 save; + UINT8 *prom = memory_region(REGION_USER1); + + if (firsttime) + { + LOG(3,("prom data:\n")); + for (promaddr = 0; promaddr < 32; promaddr++) + { + if (promaddr % 8 == 0) + LOG(3,(" %02x:", promaddr)); + LOG(3,(" %02x%s", prom[promaddr], (promaddr % 8) == 7 ? "\n" : "")); + } + firsttime = 0; + latch1 = 0; /* reset latch (??) */ + } + + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_DATA); + else + data = 0xff; + + save = data; /* save the unmodifed data for the latch */ + + promaddr = + (((data >> MAP0(type1_inmap)) & 1) << 0) | + (((data >> MAP1(type1_inmap)) & 1) << 1) | + (((data >> MAP3(type1_inmap)) & 1) << 2) | + (((data >> MAP4(type1_inmap)) & 1) << 3) | + (((data >> MAP7(type1_inmap)) & 1) << 4); + /* latch bits 2 and 6, pass bit 5, invert bit 2 */ + data = + (((prom[promaddr] >> 0) & 1) << MAP0(type1_outmap)) | + (((prom[promaddr] >> 1) & 1) << MAP1(type1_outmap)) | + ((1 - ((latch1 >> MAP2(type1_inmap)) & 1)) << MAP2(type1_outmap)) | + (((prom[promaddr] >> 2) & 1) << MAP3(type1_outmap)) | + (((prom[promaddr] >> 3) & 1) << MAP4(type1_outmap)) | + (((data >> MAP5(type1_inmap)) & 1) << MAP5(type1_outmap)) | + (((latch1 >> MAP6(type1_inmap)) & 1) << MAP6(type1_outmap)) | + (((prom[promaddr] >> 4) & 1) << MAP7(type1_outmap)); + + LOG(3,("%9.7f 6502-PC: %04x decocass_type1_latch_26_pass_5_inv_2_r(%02x): $%02x\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + + latch1 = save; /* latch the data for the next A0 == 0 read */ + } + return data; +} + + + +/*************************************************************************** + * + * TYPE1 DONGLE (DE-0061) + * - Astro Fantazia + * + * Latch bits 1 and 6, pass bit 3, invert bit 1. + * Lookup PROM DE-0061 using bits 0, 2, 4, 5, and 7 as the + * address bits; take PROM data 0-4 as data bits 0, 2, 4, 5, and 7. + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_type1_latch_16_pass_3_inv_1_r ) +{ + static UINT8 latch1; + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_STAT); + else + data = 0xff; + + data = (BIT0(data) << 0) | (BIT1(data) << 1) | 0x7c; + LOG(4,("%9.7f 6502-PC: %04x decocass_type1_latch_16_pass_3_inv_1_r(%02x): $%02x <- (%s %s)\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, + (data & 1) ? "OBF" : "-", + (data & 2) ? "IBF" : "-")); + } + else + { + offs_t promaddr; + UINT8 save; + UINT8 *prom = memory_region(REGION_USER1); + + if (firsttime) + { + LOG(3,("prom data:\n")); + for (promaddr = 0; promaddr < 32; promaddr++) + { + if (promaddr % 8 == 0) + LOG(3,(" %02x:", promaddr)); + LOG(3,(" %02x%s", prom[promaddr], (promaddr % 8) == 7 ? "\n" : "")); + } + firsttime = 0; + latch1 = 0; /* reset latch (??) */ + } + + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, I8X41_DATA); + else + data = 0xff; + + save = data; /* save the unmodifed data for the latch */ + + promaddr = + (((data >> MAP0(type1_inmap)) & 1) << 0) | + (((data >> MAP2(type1_inmap)) & 1) << 1) | + (((data >> MAP4(type1_inmap)) & 1) << 2) | + (((data >> MAP5(type1_inmap)) & 1) << 3) | + (((data >> MAP7(type1_inmap)) & 1) << 4); + /* latch bits 1 and 6, pass bit 3, invert bit 1 */ + data = + (((prom[promaddr] >> 0) & 1) << MAP0(type1_outmap)) | + ((1 - ((latch1 >> MAP1(type1_inmap)) & 1)) << MAP1(type1_outmap)) | + (((prom[promaddr] >> 1) & 1) << MAP2(type1_outmap)) | + (((data >> MAP3(type1_inmap)) & 1) << MAP3(type1_outmap)) | + (((prom[promaddr] >> 2) & 1) << MAP4(type1_outmap)) | + (((prom[promaddr] >> 3) & 1) << MAP5(type1_outmap)) | + (((latch1 >> MAP6(type1_inmap)) & 1) << MAP6(type1_outmap)) | + (((prom[promaddr] >> 4) & 1) << MAP7(type1_outmap)); + + LOG(3,("%9.7f 6502-PC: %04x decocass_type1_latch_16_pass_3_inv_1_r(%02x): $%02x\n", + attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + + latch1 = save; /* latch the data for the next A0 == 0 read */ + } + return data; +} + + + + +/*************************************************************************** + * + * TYPE2 DONGLE (CS82-007) + * - Mission X + * - Disco No 1 + * - Pro Tennis + * - Tornado + * + ***************************************************************************/ +static READ8_HANDLER( decocass_type2_r ) +{ + UINT8 data; + + if (1 == type2_xx_latch) + { + if (1 == (offset & 1)) + { + UINT8 *prom = memory_region(REGION_USER1); + data = prom[256 * type2_d2_latch + type2_promaddr]; + LOG(3,("%9.7f 6502-PC: %04x decocass_type2_r(%02x): $%02x <- prom[%03x]\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, 256 * type2_d2_latch + type2_promaddr)); + } + else + { + data = 0xff; /* floating input? */ + } + } + else + { + if (0 == (offset & E5XX_MASK)) + data = cpunum_get_reg(2, offset & 1 ? I8X41_STAT : I8X41_DATA); + else + data = offset & 0xff; + + LOG(3,("%9.7f 6502-PC: %04x decocass_type2_r(%02x): $%02x <- 8041-%s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, offset & 1 ? "STATUS" : "DATA")); + } + return data; +} + +static WRITE8_HANDLER( decocass_type2_w ) +{ + if (1 == type2_xx_latch) + { + if (1 == (offset & 1)) + { + LOG(4,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> set PROM+D2 latch", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + else + { + type2_promaddr = data; + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> set PROM addr $%02x\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, type2_promaddr)); + return; + } + } + else + { + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s ", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, offset & 1 ? "8041-CMND" : "8041 DATA")); + } + if (1 == (offset & 1)) + { + if (0xc0 == (data & 0xf0)) + { + type2_xx_latch = 1; + type2_d2_latch = (data & 0x04) ? 1 : 0; + LOG(3,("PROM:%s D2:%d", type2_xx_latch ? "on" : "off", type2_d2_latch)); + } + } + cpunum_set_reg(2, offset & 1 ? I8X41_CMND : I8X41_DATA, data); + +#ifdef MAME_DEBUG + decocass_fno(offset, data); +#endif +} + +/*************************************************************************** + * + * TYPE3 DONGLE + * - Bump 'n Jump + * - Burnin' Rubber + * - Burger Time + * - Graplop + * - Cluster Buster + * - LaPaPa + * - Fighting Ice Hockey + * - Pro Bowling + * - Night Star + * - Pro Soccer + * - Peter Pepper's Ice Cream Factory + * + ***************************************************************************/ +static READ8_HANDLER( decocass_type3_r ) +{ + UINT8 data, save; + + if (1 == (offset & 1)) + { + if (1 == type3_pal_19) + { + UINT8 *prom = memory_region(REGION_USER1); + data = prom[type3_ctrs]; + LOG(3,("%9.7f 6502-PC: %04x decocass_type3_r(%02x): $%02x <- prom[$%03x]\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, type3_ctrs)); + if (++type3_ctrs == 4096) + type3_ctrs = 0; + } + else + { + if (0 == (offset & E5XX_MASK)) + { + data = cpunum_get_reg(2, I8X41_STAT); + LOG(4,("%9.7f 6502-PC: %04x decocass_type3_r(%02x): $%02x <- 8041 STATUS\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + else + { + data = 0xff; /* open data bus? */ + LOG(4,("%9.7f 6502-PC: %04x decocass_type3_r(%02x): $%02x <- open bus\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + } + } + else + { + if (1 == type3_pal_19) + { + save = data = 0xff; /* open data bus? */ + LOG(3,("%9.7f 6502-PC: %04x decocass_type3_r(%02x): $%02x <- open bus", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + else + { + if (0 == (offset & E5XX_MASK)) + { + save = cpunum_get_reg(2, I8X41_DATA); + switch (type3_swap) + { + case TYPE3_SWAP_01: + data = + (BIT1(save) << 0) | + (type3_d0_latch << 1) | + (BIT2(save) << 2) | + (BIT3(save) << 3) | + (BIT4(save) << 4) | + (BIT5(save) << 5) | + (BIT6(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_12: + data = + (type3_d0_latch << 0) | + (BIT2(save) << 1) | + (BIT1(save) << 2) | + (BIT3(save) << 3) | + (BIT4(save) << 4) | + (BIT5(save) << 5) | + (BIT6(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_13: + data = + (type3_d0_latch << 0) | + (BIT3(save) << 1) | + (BIT2(save) << 2) | + (BIT1(save) << 3) | + (BIT4(save) << 4) | + (BIT5(save) << 5) | + (BIT6(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_24: + data = + (type3_d0_latch << 0) | + (BIT1(save) << 1) | + (BIT4(save) << 2) | + (BIT3(save) << 3) | + (BIT2(save) << 4) | + (BIT5(save) << 5) | + (BIT6(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_25: + data = + (type3_d0_latch << 0) | + (BIT1(save) << 1) | + (BIT5(save) << 2) | + (BIT3(save) << 3) | + (BIT4(save) << 4) | + (BIT2(save) << 5) | + (BIT6(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_34_0: + data = + (type3_d0_latch << 0) | + (BIT1(save) << 1) | + (BIT2(save) << 2) | + (BIT3(save) << 4) | + (BIT4(save) << 3) | + (BIT5(save) << 5) | + (BIT6(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_34_7: + data = + (BIT7(save) << 0) | + (BIT1(save) << 1) | + (BIT2(save) << 2) | + (BIT4(save) << 3) | + (BIT3(save) << 4) | + (BIT5(save) << 5) | + (BIT6(save) << 6) | + (type3_d0_latch << 7); + break; + case TYPE3_SWAP_23_56: + data = + (type3_d0_latch << 0) | + (BIT1(save) << 1) | + (BIT3(save) << 2) | + (BIT2(save) << 3) | + (BIT4(save) << 4) | + (BIT6(save) << 5) | + (BIT5(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_56: + data = + type3_d0_latch | + (BIT1(save) << 1) | + (BIT2(save) << 2) | + (BIT3(save) << 3) | + (BIT4(save) << 4) | + (BIT6(save) << 5) | + (BIT5(save) << 6) | + (BIT7(save) << 7); + break; + case TYPE3_SWAP_67: + data = + type3_d0_latch | + (BIT1(save) << 1) | + (BIT2(save) << 2) | + (BIT3(save) << 3) | + (BIT4(save) << 4) | + (BIT5(save) << 5) | + (BIT7(save) << 6) | + (BIT6(save) << 7); + break; + default: + data = + type3_d0_latch | + (BIT1(save) << 1) | + (BIT2(save) << 2) | + (BIT3(save) << 3) | + (BIT4(save) << 4) | + (BIT5(save) << 5) | + (BIT6(save) << 6) | + (BIT7(save) << 7); + } + type3_d0_latch = save & 1; + LOG(3,("%9.7f 6502-PC: %04x decocass_type3_r(%02x): $%02x '%c' <- 8041-DATA\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, (data >= 32) ? data : '.')); + } + else + { + save = 0xff; /* open data bus? */ + data = + type3_d0_latch | + (BIT1(save) << 1) | + (BIT2(save) << 2) | + (BIT3(save) << 3) | + (BIT4(save) << 4) | + (BIT5(save) << 5) | + (BIT6(save) << 7) | + (BIT7(save) << 6); + LOG(3,("%9.7f 6502-PC: %04x decocass_type3_r(%02x): $%02x '%c' <- open bus (D0 replaced with latch)\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, (data >= 32) ? data : '.')); + type3_d0_latch = save & 1; + } + } + } + + return data; +} + +static WRITE8_HANDLER( decocass_type3_w ) +{ + if (1 == (offset & 1)) + { + if (1 == type3_pal_19) + { + type3_ctrs = data << 4; + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, "LDCTRS")); + return; + } + else + if (0xc0 == (data & 0xf0)) + type3_pal_19 = 1; + } + else + { + if (1 == type3_pal_19) + { + /* write nowhere?? */ + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, "nowhere?")); + return; + } + } + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, offset & 1 ? "8041-CMND" : "8041-DATA")); + cpunum_set_reg(2, offset & 1 ? I8X41_CMND : I8X41_DATA, data); +} + +/*************************************************************************** + * + * TYPE4 DONGLE + * - Scrum Try + * Contains a 32K (EP)ROM that can be read from any byte + * boundary sequentially. The EPROM is enable after writing + * 1100xxxx to E5x1 once. Then an address is written LSB + * to E5x0 MSB to E5x1 and every read from E5x1 returns the + * next byte of the contents. + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_type4_r ) +{ + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + { + data = cpunum_get_reg(2, I8X41_STAT); + LOG(4,("%9.7f 6502-PC: %04x decocass_type4_r(%02x): $%02x <- 8041 STATUS\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + else + { + data = 0xff; /* open data bus? */ + LOG(4,("%9.7f 6502-PC: %04x decocass_type4_r(%02x): $%02x <- open bus\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + } + else + { + if (type4_latch) + { + UINT8 *prom = memory_region(REGION_USER1); + + data = prom[type4_ctrs]; + LOG(3,("%9.7f 6502-PC: %04x decocass_type4_r(%02x): $%02x '%c' <- PROM[%04x]\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, (data >= 32) ? data : '.', type4_ctrs)); + type4_ctrs = (type4_ctrs+1) & 0x7fff; + } + else + { + if (0 == (offset & E5XX_MASK)) + { + data = cpunum_get_reg(2, I8X41_DATA); + LOG(3,("%9.7f 6502-PC: %04x decocass_type4_r(%02x): $%02x '%c' <- open bus (D0 replaced with latch)\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, (data >= 32) ? data : '.')); + } + else + { + data = 0xff; /* open data bus? */ + LOG(4,("%9.7f 6502-PC: %04x decocass_type4_r(%02x): $%02x <- open bus\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + } + } + + return data; +} + +static WRITE8_HANDLER( decocass_type4_w ) +{ + if (1 == (offset & 1)) + { + if (1 == type4_latch) + { + type4_ctrs = (type4_ctrs & 0x00ff) | ((data & 0x7f) << 8); + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> CTRS MSB (%04x)\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, type4_ctrs)); + return; + } + else + if (0xc0 == (data & 0xf0)) + { + type4_latch = 1; + } + } + else + { + if (type4_latch) + { + type4_ctrs = (type4_ctrs & 0xff00) | data; + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> CTRS LSB (%04x)\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, type4_ctrs)); + return; + } + } + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, offset & 1 ? "8041-CMND" : "8041-DATA")); + cpunum_set_reg(2, offset & 1 ? I8X41_CMND : I8X41_DATA, data); +} + +/*************************************************************************** + * + * TYPE5 DONGLE + * - Boulder Dash + * Actually a NOP dongle returning 0x55 after triggering a latch + * by writing 1100xxxx to E5x1 + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_type5_r ) +{ + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + { + data = cpunum_get_reg(2, I8X41_STAT); + LOG(4,("%9.7f 6502-PC: %04x decocass_type5_r(%02x): $%02x <- 8041 STATUS\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + else + { + data = 0xff; /* open data bus? */ + LOG(4,("%9.7f 6502-PC: %04x decocass_type5_r(%02x): $%02x <- open bus\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + } + else + { + if (type5_latch) + { + data = 0x55; /* Only a fixed value? It looks like this is all we need to do */ + LOG(3,("%9.7f 6502-PC: %04x decocass_type5_r(%02x): $%02x '%c' <- fixed value???\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, (data >= 32) ? data : '.')); + } + else + { + if (0 == (offset & E5XX_MASK)) + { + data = cpunum_get_reg(2, I8X41_DATA); + LOG(3,("%9.7f 6502-PC: %04x decocass_type5_r(%02x): $%02x '%c' <- open bus (D0 replaced with latch)\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, (data >= 32) ? data : '.')); + } + else + { + data = 0xff; /* open data bus? */ + LOG(4,("%9.7f 6502-PC: %04x decocass_type5_r(%02x): $%02x <- open bus\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + } + } + + return data; +} + +static WRITE8_HANDLER( decocass_type5_w ) +{ + if (1 == (offset & 1)) + { + if (1 == type5_latch) + { + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, "latch #2??")); + return; + } + else + if (0xc0 == (data & 0xf0)) + type5_latch = 1; + } + else + { + if (type5_latch) + { + /* write nowhere?? */ + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, "nowhere?")); + return; + } + } + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, offset & 1 ? "8041-CMND" : "8041-DATA")); + cpunum_set_reg(2, offset & 1 ? I8X41_CMND : I8X41_DATA, data); +} + +/*************************************************************************** + * + * NO DONGLE + * - Flying Ball + * A NOP dongle returning the data read from cassette as is. + * + ***************************************************************************/ + +static READ8_HANDLER( decocass_nodong_r ) +{ + UINT8 data; + + if (1 == (offset & 1)) + { + if (0 == (offset & E5XX_MASK)) + { + data = cpunum_get_reg(2, I8X41_STAT); + LOG(4,("%9.7f 6502-PC: %04x decocass_nodong_r(%02x): $%02x <- 8041 STATUS\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + else + { + data = 0xff; /* open data bus? */ + LOG(4,("%9.7f 6502-PC: %04x decocass_nodong_r(%02x): $%02x <- open bus\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + } + else + { + if (0 == (offset & E5XX_MASK)) + { + data = cpunum_get_reg(2, I8X41_DATA); + LOG(3,("%9.7f 6502-PC: %04x decocass_nodong_r(%02x): $%02x '%c' <- open bus (D0 replaced with latch)\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, (data >= 32) ? data : '.')); + } + else + { + data = 0xff; /* open data bus? */ + LOG(4,("%9.7f 6502-PC: %04x decocass_nodong_r(%02x): $%02x <- open bus\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } + } + + return data; +} + +/*************************************************************************** + * + * Main dongle and 8041 interface + * + ***************************************************************************/ + +READ8_HANDLER( decocass_e5xx_r ) +{ + UINT8 data; + + /* E5x2-E5x3 and mirrors */ + if (2 == (offset & E5XX_MASK)) + { + data = + (BIT7(i8041_p1) << 0) | /* D0 = P17 - REQ/ */ + (BIT0(i8041_p2) << 1) | /* D1 = P20 - FNO/ */ + (BIT1(i8041_p2) << 2) | /* D2 = P21 - EOT/ */ + (BIT2(i8041_p2) << 3) | /* D3 = P22 - ERR/ */ + ((tape_bot_eot) << 4) | /* D4 = BOT/EOT (direct from drive) */ + (1 << 5) | /* D5 floating input */ + (1 << 6) | /* D6 floating input */ + ((1 - tape_present) << 7); /* D7 = cassette present */ + + LOG(4,("%9.7f 6502-PC: %04x decocass_e5xx_r(%02x): $%02x <- STATUS (%s%s%s%s%s%s%s%s)\n", + attotime_to_double(timer_get_time()), + activecpu_get_previouspc(), + offset, data, + data & 0x01 ? "" : "REQ/", + data & 0x02 ? "" : " FNO/", + data & 0x04 ? "" : " EOT/", + data & 0x08 ? "" : " ERR/", + data & 0x10 ? " [BOT-EOT]" : "", + data & 0x20 ? " [BIT5?]" : "", + data & 0x40 ? " [BIT6?]" : "", + data & 0x80 ? "" : " [CASS-PRESENT/]")); + } + else + { + if (decocass_dongle_r) + data = (*decocass_dongle_r)(offset); + else + data = 0xff; + } + return data; +} + +WRITE8_HANDLER( decocass_e5xx_w ) +{ + if (decocass_dongle_w) + { + (*decocass_dongle_w)(offset, data); + return; + } + + if (0 == (offset & E5XX_MASK)) + { + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> %s\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data, offset & 1 ? "8041-CMND" : "8041-DATA")); + cpunum_set_reg(2, offset & 1 ? I8X41_CMND : I8X41_DATA, data); +#ifdef MAME_DEBUG + decocass_fno(offset, data); +#endif + } + else + { + LOG(3,("%9.7f 6502-PC: %04x decocass_e5xx_w(%02x): $%02x -> dongle\n", attotime_to_double(timer_get_time()), activecpu_get_previouspc(), offset, data)); + } +} + +/*************************************************************************** + * + * DE-0091xx daughter board handler + * + * The DE-0091xx daughter board seems to be a read-only ROM board with + * two times five 4K ROMs. The only game using it (so far) is + * Treasure Island, which has 4 ROMs. + * The board's ROMs are mapped into view for reads between addresses + * 0x6000 and 0xafff by setting bit0 of address 0xe900. + * + ***************************************************************************/ + +WRITE8_HANDLER( decocass_e900_w ) +{ + de0091_enable = data & 1; + memory_set_bank(1, data & 1); + /* Perhaps the second row of ROMs is enabled by another bit. + * There is no way to verify this yet, so for now just look + * at bit 0 to enable the daughter board at reads between + * 0x6000 and 0xafff. + */ +} + +WRITE8_HANDLER( decocass_de0091_w ) +{ + /* don't allow writes to the ROMs */ + if (!de0091_enable) + decocass_charram_w(offset, data); +} + +/*************************************************************************** + * + * state save setup + * + ***************************************************************************/ +static void decocass_state_save_postload(void) +{ +#if 0 + /* fix me - this won't work anymore */ + int A; + UINT8 *mem = memory_region(REGION_CPU1); + int diff = memory_region_length(REGION_CPU1) / 2; + + memory_set_opcode_base(0, mem + diff); + + for (A = 0;A < 0x10000; A++) + decocass_w(A, mem[A]); + /* restart the timer if the tape was playing */ + if (0 != tape_dir) + timer_adjust(tape_timer, attotime_never, 0, attotime_never); +#endif +} + +/* To be called once from driver_init, i.e. decocass_init */ +void decocass_machine_state_save_init(void) +{ + state_save_register_func_postload(decocass_state_save_postload); + state_save_register_global(tape_dir); + state_save_register_global(tape_speed); + state_save_register_global(tape_time0.seconds); + state_save_register_global(tape_time0.attoseconds); + state_save_register_global(firsttime); + state_save_register_global(tape_present); + state_save_register_global(tape_blocks); + state_save_register_global(tape_length); + state_save_register_global(tape_bot_eot); + state_save_register_global(crc16_lsb); + state_save_register_global(crc16_msb); + state_save_register_global_array(tape_crc16_lsb); + state_save_register_global_array(tape_crc16_msb); + state_save_register_global(decocass_reset); + state_save_register_global(i8041_p1); + state_save_register_global(i8041_p2); + state_save_register_global(de0091_enable); + state_save_register_global(type1_inmap); + state_save_register_global(type1_outmap); + state_save_register_global(type2_d2_latch); + state_save_register_global(type2_xx_latch); + state_save_register_global(type2_promaddr); + state_save_register_global(type3_ctrs); + state_save_register_global(type3_d0_latch); + state_save_register_global(type3_pal_19); + state_save_register_global(type3_swap); + state_save_register_global(type4_ctrs); + state_save_register_global(type4_latch); + state_save_register_global(type5_latch); + state_save_register_global(decocass_sound_ack); +} + +/*************************************************************************** + * + * init machine functions (select dongle and determine tape image size) + * + ***************************************************************************/ + +static void decocass_init_common(void) +{ + UINT8 *image = memory_region(REGION_USER2); + int i, offs; + + tape_dir = 0; + tape_speed = 0; + tape_timer = timer_alloc(NULL); + + firsttime = 1; + tape_present = 1; + tape_blocks = 0; + for (i = memory_region_length(REGION_USER2) / 256 - 1; !tape_blocks && i > 0; i--) + for (offs = 256 * i; !tape_blocks && offs < 256 * i + 256; offs++) + if (image[offs]) + tape_blocks = i+1; + for (i = 0; i < tape_blocks; i++) + { + crc16_lsb = 0; + crc16_msb = 0; + for (offs = 256 * i; offs < 256 * i + 256; offs++) + { + tape_crc16(image[offs] << 7); + tape_crc16(image[offs] << 6); + tape_crc16(image[offs] << 5); + tape_crc16(image[offs] << 4); + tape_crc16(image[offs] << 3); + tape_crc16(image[offs] << 2); + tape_crc16(image[offs] << 1); + tape_crc16(image[offs] << 0); + } + tape_crc16_lsb[i] = crc16_lsb; + tape_crc16_msb[i] = crc16_msb; + } + + tape_length = tape_blocks * TAPE_CHUNK * 8 * 2 + 2 * (TAPE_LEADER + TAPE_GAP + TAPE_HOLE); + tape_time0 = attotime_mul(ATTOTIME_IN_HZ(TAPE_CLOCKRATE), TAPE_LEADER + TAPE_GAP - TAPE_HOLE); + LOG(0,("tape: %d blocks\n", tape_blocks)); + tape_bot_eot = 0; + + decocass_dongle_r = NULL; + decocass_dongle_w = NULL; + + decocass_reset = 0; + i8041_p1 = 0xff; + i8041_p2 = 0xff; + + type1_inmap = MAKE_MAP(0,1,2,3,4,5,6,7); + type1_outmap = MAKE_MAP(0,1,2,3,4,5,6,7); + + type2_d2_latch = 0; + type2_xx_latch = 0; + type2_promaddr = 0; + + type3_ctrs = 0; + type3_d0_latch = 0; + type3_pal_19 = 0; + type3_swap = 0; + + memset(decocass_quadrature_decoder, 0, sizeof(decocass_quadrature_decoder)); + decocass_sound_ack = 0; + decocass_sound_timer = timer_alloc(decocass_sound_nmi_pulse); +} + +MACHINE_RESET( decocass ) +{ + decocass_init_common(); +} + +MACHINE_RESET( ctsttape ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061)\n")); + decocass_dongle_r = decocass_type1_pass_136_r; +} + +MACHINE_RESET( chwy ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 own PROM)\n")); + decocass_dongle_r = decocass_type1_latch_27_pass_3_inv_2_r; +} + +MACHINE_RESET( clocknch ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 flip 2-3)\n")); + decocass_dongle_r = decocass_type1_latch_26_pass_3_inv_2_r; + type1_inmap = MAKE_MAP(0,1,3,2,4,5,6,7); + type1_outmap = MAKE_MAP(0,1,3,2,4,5,6,7); +} + +MACHINE_RESET( ctisland ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 flip 0-2)\n")); + decocass_dongle_r = decocass_type1_latch_26_pass_3_inv_2_r; + type1_inmap = MAKE_MAP(2,1,0,3,4,5,6,7); + type1_outmap = MAKE_MAP(2,1,0,3,4,5,6,7); +} + +MACHINE_RESET( csuperas ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 flip 4-5)\n")); + decocass_dongle_r = decocass_type1_latch_26_pass_3_inv_2_r; + type1_inmap = MAKE_MAP(0,1,2,3,5,4,6,7); + type1_outmap = MAKE_MAP(0,1,2,3,5,4,6,7); +} + +MACHINE_RESET( castfant ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061)\n")); + decocass_dongle_r = decocass_type1_latch_16_pass_3_inv_1_r; +} + +MACHINE_RESET( cluckypo ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 flip 1-3)\n")); + decocass_dongle_r = decocass_type1_latch_26_pass_3_inv_2_r; + type1_inmap = MAKE_MAP(0,3,2,1,4,5,6,7); + type1_outmap = MAKE_MAP(0,3,2,1,4,5,6,7); +} + +MACHINE_RESET( cterrani ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 straight)\n")); + decocass_dongle_r = decocass_type1_latch_26_pass_3_inv_2_r; + type1_inmap = MAKE_MAP(0,1,2,3,4,5,6,7); + type1_outmap = MAKE_MAP(0,1,2,3,4,5,6,7); +} + +MACHINE_RESET( cexplore ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 own PROM)\n")); + decocass_dongle_r = decocass_type1_latch_26_pass_5_inv_2_r; +} + +MACHINE_RESET( cprogolf ) +{ + decocass_init_common(); + LOG(0,("dongle type #1 (DE-0061 flip 0-1)\n")); + decocass_dongle_r = decocass_type1_latch_26_pass_3_inv_2_r; + type1_inmap = MAKE_MAP(1,0,2,3,4,5,6,7); + type1_outmap = MAKE_MAP(1,0,2,3,4,5,6,7); +} + +MACHINE_RESET( cmissnx ) +{ + decocass_init_common(); + LOG(0,("dongle type #2 (CS82-007)\n")); + decocass_dongle_r = decocass_type2_r; + decocass_dongle_w = decocass_type2_w; +} + +MACHINE_RESET( cdiscon1 ) +{ + decocass_init_common(); + LOG(0,("dongle type #2 (CS82-007)\n")); + decocass_dongle_r = decocass_type2_r; + decocass_dongle_w = decocass_type2_w; +} + +MACHINE_RESET( cptennis ) +{ + decocass_init_common(); + LOG(0,("dongle type #2 (CS82-007)\n")); + decocass_dongle_r = decocass_type2_r; + decocass_dongle_w = decocass_type2_w; +} + +MACHINE_RESET( ctornado ) +{ + decocass_init_common(); + LOG(0,("dongle type #2 (CS82-007)\n")); + decocass_dongle_r = decocass_type2_r; + decocass_dongle_w = decocass_type2_w; +} + +MACHINE_RESET( cbnj ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_67; +} + +MACHINE_RESET( cburnrub ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_67; +} + +MACHINE_RESET( cbtime ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_12; +} + +MACHINE_RESET( cgraplop ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_56; +} + +MACHINE_RESET( cgraplp2 ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_67; +} + +MACHINE_RESET( clapapa ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_34_7; +} + +MACHINE_RESET( cfghtice ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_25; +} + +MACHINE_RESET( cprobowl ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_34_0; +} + +MACHINE_RESET( cnightst ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_13; +} + +MACHINE_RESET( cprosocc ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_24; +} + +MACHINE_RESET( cppicf ) +{ + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_01; +} + +MACHINE_RESET( cscrtry ) +{ + decocass_init_common(); + LOG(0,("dongle type #4 (32K ROM)\n")); + decocass_dongle_r = decocass_type4_r; + decocass_dongle_w = decocass_type4_w; +} + +MACHINE_RESET( cbdash ) +{ + decocass_init_common(); + LOG(0,("dongle type #5 (NOP)\n")); + decocass_dongle_r = decocass_type5_r; + decocass_dongle_w = decocass_type5_w; +} + +MACHINE_RESET( cflyball ) +{ + decocass_init_common(); + LOG(0,("no dongle\n")); + decocass_dongle_r = decocass_nodong_r; +} + +MACHINE_RESET( czeroize ) +{ + UINT8 *mem = memory_region(REGION_USER1); + decocass_init_common(); + LOG(0,("dongle type #3 (PAL)\n")); + decocass_dongle_r = decocass_type3_r; + decocass_dongle_w = decocass_type3_w; + type3_swap = TYPE3_SWAP_23_56; + + /* + * FIXME: remove if the original ROM is available. + * The Zeroize 6502 code at 0x3707 issues LODCTRS with 0x8a, + * and expects to read 0x18 from 0x08a0 ff. within 7 bytes. + * This hack seems to be sufficient to get around + * the missing dongle ROM contents and play the game. + */ + memset(mem,0x00,0x1000); + mem[0x08a0] = 0x18; +} + +/*************************************************************************** + * + * 8041 port handlers + * + ***************************************************************************/ + +static void tape_stop(void) +{ + /* remember time */ + tape_time0 = decocass_adjust_tape_time(tape_time0); + + timer_adjust(tape_timer, attotime_never, 0, attotime_never); +} + + +WRITE8_HANDLER( i8041_p1_w ) +{ + static int i8041_p1_old; + + if (data != i8041_p1_old) + { + LOG(4,("%9.7f 8041-PC: %03x i8041_p1_w: $%02x (%s%s%s%s%s%s%s%s)\n", + attotime_to_double(timer_get_time()), + activecpu_get_previouspc(), + data, + data & 0x01 ? "" : "DATA-WRT", + data & 0x02 ? "" : " DATA-CLK", + data & 0x04 ? "" : " FAST", + data & 0x08 ? "" : " BIT3", + data & 0x10 ? "" : " REW", + data & 0x20 ? "" : " FWD", + data & 0x40 ? "" : " WREN", + data & 0x80 ? "" : " REQ")); + i8041_p1_old = data; + } + + /* change in REW signal ? */ + if ((data ^ i8041_p1) & 0x10) + { + tape_stop(); + if (0 == (data & 0x10)) + { + LOG(2,("tape %5.4fs: rewind\n", attotime_to_double(tape_time0))); + tape_dir = -1; + timer_adjust(tape_timer, attotime_never, 0, attotime_never); + set_led_status(0, 1); + } + else + { + tape_dir = 0; + tape_speed = 0; + LOG(2,("tape %5.4fs: stopped\n", attotime_to_double(tape_time0))); +#if TAPE_UI_DISPLAY + popmessage(" [%05.1fs] ", attotime_to_double(tape_time0)); +#endif + set_led_status(0, 0); + } + } + + /* change in FWD signal ? */ + if ((data ^ i8041_p1) & 0x20) + { + tape_stop(); + if (0 == (data & 0x20)) + { + LOG(2,("tape %5.4fs: forward\n", attotime_to_double(tape_time0))); + tape_dir = +1; + timer_adjust(tape_timer, attotime_never, 0, attotime_never); + set_led_status(0, 1); + } + else + { + tape_dir = 0; + tape_speed = 0; + LOG(2,("tape %5.4fs: stopped\n", attotime_to_double(tape_time0))); +#if TAPE_UI_DISPLAY + popmessage(" [%05.1fs] ", attotime_to_double(tape_time0)); +#endif + set_led_status(0, 0); + } + } + + /* change in FAST signal ? */ + if (tape_timer && (data ^ i8041_p1) & 0x04) + { + tape_stop(); + tape_speed = (0 == (data & 0x04)) ? 1 : 0; + + if (tape_dir < 0) + { + LOG(2,("tape: fast rewind %s\n", (0 == (data & 0x04)) ? "on" : "off")); + tape_dir = (tape_speed) ? -7 : -1; + timer_adjust(tape_timer, attotime_never, 0, attotime_never); + } + else + if (tape_dir > 0) + { + LOG(2,("tape: fast forward %s\n", (0 == (data & 0x04)) ? "on" : "off")); + tape_dir = (tape_speed) ? +7 : +1; + timer_adjust(tape_timer, attotime_never, 0, attotime_never); + } + } + + i8041_p1 = data; +} + +READ8_HANDLER( i8041_p1_r ) +{ + UINT8 data = i8041_p1; + static int i8041_p1_old; + + if (data != i8041_p1_old) + { + LOG(4,("%9.7f 8041-PC: %03x i8041_p1_r: $%02x (%s%s%s%s%s%s%s%s)\n", + attotime_to_double(timer_get_time()), + activecpu_get_previouspc(), + data, + data & 0x01 ? "" : "DATA-WRT", + data & 0x02 ? "" : " DATA-CLK", + data & 0x04 ? "" : " FAST", + data & 0x08 ? "" : " BIT3", + data & 0x10 ? "" : " REW", + data & 0x20 ? "" : " FWD", + data & 0x40 ? "" : " WREN", + data & 0x80 ? "" : " REQ")); + i8041_p1_old = data; + } + return data; +} + +WRITE8_HANDLER( i8041_p2_w ) +{ + static int i8041_p2_old; + + if (data != i8041_p2_old) + { + LOG(4,("%9.7f 8041-PC: %03x i8041_p2_w: $%02x (%s%s%s%s%s%s%s%s)\n", + attotime_to_double(timer_get_time()), + activecpu_get_previouspc(), + data, + data & 0x01 ? "" : "FNO/", + data & 0x02 ? "" : " EOT/", + data & 0x04 ? "" : " ERR/", + data & 0x08 ? "" : " OUT3?/", + data & 0x10 ? " [IN4]" : "", + data & 0x20 ? " [BOT-EOT]" : "", + data & 0x40 ? " [RCLK]" : "", + data & 0x80 ? " [RDATA]" : "")); + i8041_p2_old = data; + } + i8041_p2 = data; +} + +READ8_HANDLER( i8041_p2_r ) +{ + UINT8 data; + static int i8041_p2_old; + + tape_update(); + + data = i8041_p2; + + if (data != i8041_p2_old) + { + LOG(4,("%9.7f 8041-PC: %03x i8041_p2_r: $%02x (%s%s%s%s%s%s%s%s)\n", + attotime_to_double(timer_get_time()), + activecpu_get_previouspc(), + data, + data & 0x01 ? "" : "FNO/", + data & 0x02 ? "" : " EOT/", + data & 0x04 ? "" : " ERR/", + data & 0x08 ? "" : " OUT3?/", + data & 0x10 ? " [IN4]" : "", + data & 0x20 ? " [BOT-EOT]" : "", + data & 0x40 ? " [RCLK]" : "", + data & 0x80 ? " [RDATA]" : "")); + i8041_p2_old = data; + } + return data; +} + + |