diff options
Diffstat (limited to 'src/mess/machine/64h156.c')
-rw-r--r-- | src/mess/machine/64h156.c | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/src/mess/machine/64h156.c b/src/mess/machine/64h156.c new file mode 100644 index 00000000000..301d136a1e0 --- /dev/null +++ b/src/mess/machine/64h156.c @@ -0,0 +1,714 @@ +/********************************************************************** + + Commodore 64H156 Gate Array emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +/* + + TODO: + + http://staff.washington.edu/rrcc/uwweb/1541early/1540-2.GIF + + - model disk rotation for proper track alignment + - write circuitry + - cycle exact M6502 + - cycle exact VIA + - refactor to use modern floppy system + + - get these running and we're golden + - Quiwi (speed change within track) + - Defender of the Crown (V-MAX! v2, density checks) + - Test Drive / Cabal (HLS, sub-cycle jitter) + - Galaxian (?, needs 100% accurate VIA) + +*/ + +#include "emu.h" +#include "64h156.h" +#include "formats/g64_dsk.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + +#define ATN (m_atni ^ m_atna) + +#define CYCLES_UNTIL_ANALOG_DESYNC 288 // 18 us + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type C64H156 = &device_creator<c64h156_device>; + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void c64h156_device::device_config_complete() +{ + // inherit a copy of the static data + const c64h156_interface *intf = reinterpret_cast<const c64h156_interface *>(static_config()); + if (intf != NULL) + *static_cast<c64h156_interface *>(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_out_atn_cb, 0, sizeof(m_out_atn_cb)); + memset(&m_out_sync_cb, 0, sizeof(m_out_sync_cb)); + memset(&m_out_byte_cb, 0, sizeof(m_out_byte_cb)); + } +} + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// set_atn_line - +//------------------------------------------------- + +inline void c64h156_device::set_atn_line() +{ + m_out_atn_func(ATN); +} + + +//------------------------------------------------- +// read_current_track - +//------------------------------------------------- + +inline void c64h156_device::read_current_track() +{ + int track_length = G64_BUFFER_SIZE; + + // read track data + floppy_drive_read_track_data_info_buffer(m_image, m_side, m_track_buffer, &track_length); + + // extract track length + m_track_len = floppy_drive_get_current_track_size(m_image, m_side); + + // set bit pointer to track start + m_buffer_pos = 0; + m_bit_pos = 7; + m_bit_count = 0; + m_zero_count = 0; + + if (m_track_len) + { + memcpy(m_speed_buffer, m_track_buffer + m_track_len, G64_SPEED_BLOCK_SIZE); + + update_cycles_until_next_bit(); + } +} + + +//------------------------------------------------- +// update_cycles_until_next_bit - +//------------------------------------------------- + +inline void c64h156_device::update_cycles_until_next_bit() +{ + int speed_offset = m_buffer_pos / 4; + int speed_shift = (3 - (m_buffer_pos % 4)) * 2; + + UINT8 speed = m_speed_buffer[speed_offset]; + + int ds = (speed >> speed_shift) & 0x03; + + m_cycles_until_next_bit = (16 - ds) * 4; + + if (LOG) logerror("buff %04x:%u speed %04x shift %u ds %u cycles %u\n", m_buffer_pos, m_bit_pos, speed_offset, speed_shift, ds, m_cycles_until_next_bit); +} + + +//------------------------------------------------- +// receive_bit - receive bit +//------------------------------------------------- + +inline void c64h156_device::receive_bit() +{ + if (!m_track_len) + { + m_bit_sync = 0; + } + else + { + if (m_cycles_until_next_bit == 0) + { + m_bit_sync = BIT(m_track_buffer[m_buffer_pos], m_bit_pos); + + if (m_bit_sync) + { + m_zero_count = 0; + m_cycles_until_random_flux = (rand() % 31) + 289; + } + else + { + m_zero_count++; + } + + if (m_zero_count >= m_cycles_until_random_flux) + { + // receive phantom bit + if (LOG) logerror("PHANTOM BIT SYNC 1 after %u cycles\n", m_zero_count); + + m_bit_sync = 1; + + m_zero_count = 0; + m_cycles_until_random_flux = (rand() % 367) + 33; + } + else + { + if (LOG) logerror("BIT SYNC %u\n", m_bit_sync); + } + + m_shift <<= 1; + m_shift |= m_bit_sync; + + m_bit_pos--; + m_bit_count++; + + if (m_bit_pos < 0) + { + m_bit_pos = 7; + m_buffer_pos++; + + if (m_buffer_pos >= m_track_len) + { + // loop to the start of the track + m_buffer_pos = 0; + } + } + + update_cycles_until_next_bit(); + } + + m_cycles_until_next_bit--; + } +} + + +//------------------------------------------------- +// decode_bit - +//------------------------------------------------- + +inline void c64h156_device::decode_bit() +{ + // UE7 + + bool ue7_tc = false; + + if (!m_last_bit_sync && m_bit_sync) + { + m_ue7 = m_ds; + } + else + { + m_ue7++; + + if (m_ue7 == 16) + { + m_ue7 = m_ds; + ue7_tc = true; + } + } + + if (LOG) logerror("UE7 CTR %01x TC %u, ", m_ue7, ue7_tc); + + // UF4 + + if (!m_last_bit_sync && m_bit_sync) + { + m_uf4 = 0; + + if (LOG) logerror("--"); + } + else + { + if (!m_ue7_tc && ue7_tc) + { + m_uf4++; + m_uf4 &= 0x0f; + + if (LOG) logerror("++"); + } + else + { + if (LOG) logerror(" "); + } + } + + m_last_bit_sync = m_bit_sync; + m_ue7_tc = ue7_tc; + + int uf4_qa = BIT(m_uf4, 0); + int uf4_qb = BIT(m_uf4, 1); + int uf4_qc = BIT(m_uf4, 2); + int uf4_qd = BIT(m_uf4, 3); + + int ue5a = !(uf4_qc || uf4_qd); + + if (LOG) logerror("UF4 CTR %01x %u%u%u%u UE5A %u, ", m_uf4, uf4_qd, uf4_qc, uf4_qb, uf4_qa, ue5a); + + if (!m_uf4_qb && uf4_qb) + { + // shift bits thru flip-flops + m_u4b = m_u4a; + m_u4a = BIT(m_ud2, 7); + + // shift in data bit + m_ud2 <<= 1; + m_ud2 |= ue5a; + + if (LOG) logerror("<<"); + } + else + { + if (LOG) logerror(" "); + } + + if (LOG) logerror("UD2 %u%u%u%u%u%u%u%u%u%u : %02x (%02x), ", m_u4b, m_u4a, BIT(m_ud2, 7), BIT(m_ud2, 6), BIT(m_ud2, 5), BIT(m_ud2, 4), BIT(m_ud2, 3), BIT(m_ud2, 2), BIT(m_ud2, 1), BIT(m_ud2, 0), m_ud2, m_shift & 0xff); + + // UE3 + + int block_sync = !(m_oe && (m_ud2 == 0xff) && m_u4a && m_u4b); + + if (LOG) logerror("SYNC %u, ", block_sync); + + if (!block_sync) + { + // load UE3 + m_ue3 = 8; // pin D is floating and TTL inputs float high + + if (LOG) logerror("--"); + } + else + { + if (m_block_sync && !m_uf4_qb && uf4_qb) + { + // clock UE3 + m_ue3++; + + if (m_ue3 == 16) + { + m_ue3 = 0; + } + + if (LOG) logerror("++"); + } + else + { + if (LOG) logerror(" "); + } + } + + int ue3_qa = BIT(m_ue3, 0); + int ue3_qb = BIT(m_ue3, 1); + int ue3_qc = BIT(m_ue3, 2); + + int uf3a = !(ue3_qa && ue3_qb && ue3_qc); + int uc1b = !uf3a; // schmitt trigger + + if (LOG) logerror("UE3 CTR %01x UF3A %u UC1B %u, ", m_ue3, uf3a, uc1b); + + int byte_sync = !(uc1b && m_soe && !uf4_qb); + + if (LOG) logerror("BYTE %u SOE %u\n", m_byte_sync, m_soe); + + // UD3 + + int uf3b = !(uc1b && uf4_qa && uf4_qb); + + if (!uf3b) + { + m_ud3 = m_via_pa; + } + else if (!m_uf4_qb && uf4_qb) + { + // shift out bits + int ud3_qh = BIT(m_ud3, 0); + m_ud3 >>= 1; + + int uf5b = !(!uf4_qb && ud3_qh); + + if (!m_oe && m_wp) + { + // TODO write bit to disk + if (LOG) logerror("WRITE BIT %u\n", uf5b); + } + } + + // prepare for next cycle + + if (m_block_sync != block_sync) + { + m_block_sync = block_sync; + m_out_sync_func(m_block_sync); + } + + if (m_byte_sync != byte_sync) + { + m_byte_sync = byte_sync; + m_out_byte_func(m_byte_sync); + } + + m_uf4_qb = uf4_qb; + + m_bit_sync = 0; +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// c64h156_device - constructor +//------------------------------------------------- + +c64h156_device::c64h156_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, C64H156, "64H156", tag, owner, clock), + device_execute_interface(mconfig, *this), + m_icount(0), + m_image(*this->owner(), FLOPPY_0), + m_side(0), + m_track_buffer(NULL), + m_track_len(0), + m_buffer_pos(0), + m_bit_pos(0), + m_bit_count(0), + m_stp(-1), + m_mtr(0), + m_accl(1), + m_ds(0), + m_soe(0), + m_oe(0), + m_atni(1), + m_atna(1), + m_last_bit_sync(0), + m_bit_sync(0), + m_byte_sync(1), + m_block_sync(1), + m_ue7(0), + m_ue7_tc(0), + m_uf4(0), + m_uf4_qb(0), + m_ud2(0), + m_u4a(0), + m_u4b(0), + m_ue3(0), + m_uc1b(0), + m_wp(0) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void c64h156_device::device_start() +{ + // set our instruction counter + m_icountptr = &m_icount; + + // allocate track buffer + m_track_buffer = auto_alloc_array(machine(), UINT8, G64_BUFFER_SIZE); + m_speed_buffer = auto_alloc_array(machine(), UINT8, G64_SPEED_BLOCK_SIZE); + + // resolve callbacks + m_out_atn_func.resolve(m_out_atn_cb, *this); + m_out_sync_func.resolve(m_out_sync_cb, *this); + m_out_byte_func.resolve(m_out_byte_cb, *this); + + // register for state saving + save_item(NAME(m_shift)); + save_item(NAME(m_side)); + save_pointer(NAME(m_track_buffer), G64_BUFFER_SIZE); + save_pointer(NAME(m_speed_buffer), G64_SPEED_BLOCK_SIZE); + save_item(NAME(m_track_len)); + save_item(NAME(m_buffer_pos)); + save_item(NAME(m_bit_pos)); + save_item(NAME(m_bit_count)); + save_item(NAME(m_cycles_until_next_bit)); + save_item(NAME(m_zero_count)); + save_item(NAME(m_cycles_until_random_flux)); + save_item(NAME(m_stp)); + save_item(NAME(m_mtr)); + save_item(NAME(m_accl)); + save_item(NAME(m_ds)); + save_item(NAME(m_soe)); + save_item(NAME(m_oe)); + save_item(NAME(m_atni)); + save_item(NAME(m_atna)); + save_item(NAME(m_last_bit_sync)); + save_item(NAME(m_bit_sync)); + save_item(NAME(m_byte_sync)); + save_item(NAME(m_block_sync)); + save_item(NAME(m_ue7)); + save_item(NAME(m_ue7_tc)); + save_item(NAME(m_uf4)); + save_item(NAME(m_uf4_qb)); + save_item(NAME(m_ud2)); + save_item(NAME(m_u4a)); + save_item(NAME(m_u4b)); + save_item(NAME(m_ue3)); + save_item(NAME(m_uc1b)); + save_item(NAME(m_via_pa)); + save_item(NAME(m_ud3)); + save_item(NAME(m_wp)); +} + + +//------------------------------------------------- +// execute_run - +//------------------------------------------------- + +void c64h156_device::execute_run() +{ + do + { + if (m_mtr) + { + receive_bit(); + } + + decode_bit(); + + m_icount--; + } while (m_icount > 0); +} + + +//------------------------------------------------- +// yb_r - +//------------------------------------------------- + +READ8_MEMBER( c64h156_device::yb_r ) +{ + UINT8 data = 0; + + if (m_soe) + { + data = m_ud2; + } + + if (LOG) logerror("YB read %02x:%02x\n", m_ud2, data); + + return data; +} + + +//------------------------------------------------- +// yb_w - +//------------------------------------------------- + +WRITE8_MEMBER( c64h156_device::yb_w ) +{ + m_via_pa = data; +} + + +//------------------------------------------------- +// test_w - test write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::test_w ) +{ +} + + +//------------------------------------------------- +// accl_w - +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::accl_w ) +{ + m_accl = state; +} + + +//------------------------------------------------- +// sync_r - sync read +//------------------------------------------------- + +READ_LINE_MEMBER( c64h156_device::sync_r ) +{ + return m_block_sync; +} + + +//------------------------------------------------- +// byte_r - byte ready read +//------------------------------------------------- + +READ_LINE_MEMBER( c64h156_device::byte_r ) +{ + return m_byte_sync; +} + + +//------------------------------------------------- +// mtr_w - motor write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::mtr_w ) +{ + if (m_mtr != state) + { + if (LOG) logerror("MTR %u\n", state); + + if (state) + { + // read track data + read_current_track(); + } + + floppy_mon_w(m_image, !state); + + m_mtr = state; + } +} + + +//------------------------------------------------- +// oe_w - output enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::oe_w ) +{ + if (LOG) logerror("OE %u\n", state); + + m_oe = state; +} + + +//------------------------------------------------- +// soe_w - SO enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::soe_w ) +{ + if (LOG) logerror("SOE %u\n", state); + + m_soe = state; +} + + +//------------------------------------------------- +// atn_r - serial attention read +//------------------------------------------------- + +READ_LINE_MEMBER( c64h156_device::atn_r ) +{ + return ATN; +} + + +//------------------------------------------------- +// atni_w - serial attention input write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::atni_w ) +{ + if (LOG) logerror("ATNI %u\n", state); + + m_atni = state; + + set_atn_line(); +} + + +//------------------------------------------------- +// atna_w - serial attention acknowledge write +//------------------------------------------------- + +WRITE_LINE_MEMBER( c64h156_device::atna_w ) +{ + if (LOG) logerror("ATNA %u\n", state); + + m_atna = state; + + set_atn_line(); +} + + +//------------------------------------------------- +// stp_w - +//------------------------------------------------- + +void c64h156_device::stp_w(int data) +{ + if (m_mtr && (m_stp != data)) + { + int tracks = 0; + + switch (m_stp) + { + case 0: if (data == 1) tracks++; else if (data == 3) tracks--; break; + case 1: if (data == 2) tracks++; else if (data == 0) tracks--; break; + case 2: if (data == 3) tracks++; else if (data == 1) tracks--; break; + case 3: if (data == 0) tracks++; else if (data == 2) tracks--; break; + } + + if (tracks != 0) + { + // step read/write head + floppy_drive_seek(m_image, tracks); + + // read new track data + read_current_track(); + } + + m_stp = data; + } +} + + +//------------------------------------------------- +// ds_w - density select +//------------------------------------------------- + +void c64h156_device::ds_w(int data) +{ + m_ds = data; +} + + +//------------------------------------------------- +// on_disk_changed - +//------------------------------------------------- + +void c64h156_device::on_disk_changed(int wp) +{ + m_wp = wp; + + read_current_track(); +} + + +//------------------------------------------------- +// set_side - +//------------------------------------------------- + +void c64h156_device::set_side(int side) +{ + m_side = side; +} |