summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/ieee488/hp9895.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/ieee488/hp9895.cpp')
-rw-r--r--src/devices/bus/ieee488/hp9895.cpp345
1 files changed, 166 insertions, 179 deletions
diff --git a/src/devices/bus/ieee488/hp9895.cpp b/src/devices/bus/ieee488/hp9895.cpp
index ee23db8c6cb..ffc7ae29d70 100644
--- a/src/devices/bus/ieee488/hp9895.cpp
+++ b/src/devices/bus/ieee488/hp9895.cpp
@@ -56,13 +56,14 @@
#include "emu.h"
#include "hp9895.h"
+#include "formats/fs_hp98x5.h"
#include "formats/hpi_dsk.h"
-// Debugging
-#define VERBOSE 1
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
-#define VERBOSE_0 0
-#define LOG_0(x) do { if (VERBOSE_0) logerror x; } while (0)
+#define LOG_LEVEL0 (0x1U << 1)
+#define LOG_LEVEL1 (0x3U << 1)
+
+#define VERBOSE (LOG_LEVEL1)
+#include "logmacro.h"
// Macros to clear/set single bits
#define BIT_MASK(n) (1U << (n))
@@ -116,13 +117,6 @@
#define REG_SWITCHES_TIMEOUT_BIT 6 // TIMEOUT (1)
#define REG_SWITCHES_AMDT_BIT 7 // Address mark detected (1)
-// Timers
-enum {
- TIMEOUT_TMR_ID,
- BYTE_TMR_ID,
- HALF_BIT_TMR_ID
-};
-
// Timings
#define TIMEOUT_MSEC 450 // Timeout duration (ms)
#define HPMODE_BIT_FREQ 500000 // HP-mode bit frequency (Hz)
@@ -144,7 +138,7 @@ hp9895_device::hp9895_device(const machine_config &mconfig, const char *tag, dev
device_ieee488_interface(mconfig, *this),
m_cpu(*this , "cpu"),
m_phi(*this , "phi"),
- m_drives{{*this , "floppy0"} , {*this , "floppy1"}},
+ m_drives(*this , "floppy%u" , 0U),
m_switches{*this , "switches"}
{
}
@@ -198,9 +192,9 @@ void hp9895_device::device_start()
save_item(NAME(m_hiden));
save_item(NAME(m_mgnena));
- m_timeout_timer = timer_alloc(TIMEOUT_TMR_ID);
- m_byte_timer = timer_alloc(BYTE_TMR_ID);
- m_half_bit_timer = timer_alloc(HALF_BIT_TMR_ID);
+ m_timeout_timer = timer_alloc(FUNC(hp9895_device::timeout_timer_tick), this);
+ m_byte_timer = timer_alloc(FUNC(hp9895_device::byte_timer_tick), this);
+ m_half_bit_timer = timer_alloc(FUNC(hp9895_device::half_bit_timer_tick), this);
for (auto& d : m_drives) {
d->get_device()->setup_ready_cb(floppy_image_device::ready_cb(&hp9895_device::floppy_ready_cb , this));
@@ -236,159 +230,150 @@ void hp9895_device::device_reset()
m_half_bit_timer->reset();
}
-void hp9895_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(hp9895_device::timeout_timer_tick)
{
- switch (id) {
- case TIMEOUT_TMR_ID:
- LOG(("Timeout!\n"));
- m_timeout = true;
- if (m_mgnena) {
- // CPU is resumed by timeout if MGNENA=1
- m_cpu->trigger(1);
- }
- break;
+ LOGMASKED(LOG_LEVEL1, "Timeout\n");
+ m_timeout = true;
+ if (m_mgnena) {
+ // CPU is resumed by timeout if MGNENA=1
+ m_cpu->trigger(1);
+ }
+}
- case BYTE_TMR_ID:
- {
- if (m_accdata) {
- // Resume CPU when it's waiting for SDOK
- m_cpu->trigger(1);
+TIMER_CALLBACK_MEMBER(hp9895_device::byte_timer_tick)
+{
+ if (m_accdata) {
+ // Resume CPU when it's waiting for SDOK
+ m_cpu->trigger(1);
+ } else {
+ // No access to data register by CPU
+ LOGMASKED(LOG_LEVEL1, "Data overrun\n");
+ m_overrun = true;
+ }
+ m_accdata = false;
+
+ m_crcerr_syn = m_crc != 0;
+
+ if (!BIT(m_cntl_reg , REG_CNTL_CRCON_BIT)) {
+ // CRC not enabled, keep it in preset state (all ones)
+ preset_crc();
+ }
+
+ attotime sdok_time{machine().time()};
+ LOGMASKED(LOG_LEVEL0, "SDOK @ %.06f\n" , sdok_time.as_double());
+ bool do_crc_upd = true;
+ if (BIT(m_cntl_reg , REG_CNTL_WRITON_BIT)) {
+ // Writing
+ m_pll.commit(get_write_device() , sdok_time);
+ m_pll.ctime = sdok_time;
+
+ // Check for AMDT when in loopback mode
+ if (!m_lckup && !m_amdt && BIT(m_cntl_reg , REG_CNTL_READON_BIT)) {
+ if (m_hiden) {
+ m_amdt = m_data_sr != 0xff;
} else {
- // No access to data register by CPU
- LOG(("Data overrun!\n"));
- m_overrun = true;
+ m_amdt = m_data_sr != 0;
}
- m_accdata = false;
-
- m_crcerr_syn = m_crc != 0;
+ }
- if (!BIT(m_cntl_reg , REG_CNTL_CRCON_BIT)) {
- // CRC not enabled, keep it in preset state (all ones)
- preset_crc();
+ LOGMASKED(LOG_LEVEL0, "WR D=%02x/C=%02x\n" , m_data_sr , m_clock_sr);
+ do_crc_upd = false;
+ for (unsigned i = 0; i < 8; i++) {
+ bool clock_bit;
+ bool data_bit;
+
+ clock_bit = shift_sr(m_clock_sr, false);
+ data_bit = shift_sr(m_data_sr, true);
+
+ if (BIT(m_cntl_reg , REG_CNTL_CRCOUT_BIT)) {
+ // Substitute data bits from DSR with those from CRC when CRCOUT=1
+ data_bit = BIT(m_crc , 15);
+ m_crc <<= 1;
+ } else if (BIT(m_cntl_reg , REG_CNTL_CRCON_BIT)) {
+ // Update CRC
+ update_crc(data_bit);
}
+ write_bit(data_bit, clock_bit);
+ }
+ // When shifting is done DSR is filled with 1s and CSR with 0s
+ }
+ if (BIT(m_cntl_reg , REG_CNTL_READON_BIT)) {
+ // Reading
+ m_pll.ctime = sdok_time;
- attotime sdok_time{machine().time()};
- LOG_0(("SDOK @ %.06f\n" , sdok_time.as_double()));
- bool do_crc_upd = true;
+ for (unsigned i = 0; i < 8; i++) {
+ read_bit(do_crc_upd);
+ }
+ LOGMASKED(LOG_LEVEL0, "RD D=%02x/C=%02x\n" , m_data_sr , m_clock_sr);
+ }
+ LOGMASKED(LOG_LEVEL0, "next SDOK @ %.06f\n" , m_pll.ctime.as_double());
+ m_byte_timer->adjust(m_pll.ctime - sdok_time);
+}
+
+TIMER_CALLBACK_MEMBER(hp9895_device::half_bit_timer_tick)
+{
+ m_pll.ctime = machine().time();
+ if (m_lckup) {
+ // Trying to lock on synchronization bytes
+ attotime edge;
+ attotime tm;
+ get_next_transition(m_pll.ctime, edge);
+ bool half_bit0 = m_pll.feed_read_data(tm , edge , attotime::never);
+ get_next_transition(m_pll.ctime, edge);
+ bool half_bit1 = m_pll.feed_read_data(tm , edge , attotime::never);
+ if (half_bit0 == half_bit1) {
+ // If half bits are equal, no synch
+ LOGMASKED(LOG_LEVEL0, "Reset sync_cnt\n");
+ m_sync_cnt = 0;
+ } else if (++m_sync_cnt >= MIN_SYNC_BITS) {
+ // Synchronized, now wait for AM
+ LOGMASKED(LOG_LEVEL0, "Synchronized @ %.6f\n" , machine().time().as_double());
+ m_lckup = false;
if (BIT(m_cntl_reg , REG_CNTL_WRITON_BIT)) {
- // Writing
- m_pll.commit(get_write_device() , sdok_time);
- m_pll.ctime = sdok_time;
-
- // Check for AMDT when in loopback mode
- if (!m_lckup && !m_amdt && BIT(m_cntl_reg , REG_CNTL_READON_BIT)) {
- if (m_hiden) {
- m_amdt = m_data_sr != 0xff;
- } else {
- m_amdt = m_data_sr != 0;
- }
+ // When loopback is active, leave AM detection to byte timer as
+ // byte boundary is already synchronized
+ m_half_bit_timer->reset();
+ return;
+ } else {
+ // Align with bit cell
+ // Synchronization bits in HP mode: 32x 1s -> C/D bits = 01010101...
+ // Synchronization bits in IBM mode: 32x 0s -> C/D bits = 10101010...
+ if (m_hiden != half_bit1) {
+ // Discard 1/2 bit cell if synchronization achieved in the clock part
+ get_next_transition(m_pll.ctime, edge);
+ m_pll.feed_read_data(tm , edge , attotime::never);
}
-
- LOG_0(("WR D=%02x/C=%02x\n" , m_data_sr , m_clock_sr));
- do_crc_upd = false;
- for (unsigned i = 0; i < 8; i++) {
- bool clock_bit;
- bool data_bit;
-
- clock_bit = shift_sr(m_clock_sr, false);
- data_bit = shift_sr(m_data_sr, true);
-
- if (BIT(m_cntl_reg , REG_CNTL_CRCOUT_BIT)) {
- // Substitute data bits from DSR with those from CRC when CRCOUT=1
- data_bit = BIT(m_crc , 15);
- m_crc <<= 1;
- } else if (BIT(m_cntl_reg , REG_CNTL_CRCON_BIT)) {
- // Update CRC
- update_crc(data_bit);
- }
- write_bit(data_bit, clock_bit);
+ // Load CSR & DSR as they are after synchronization bits
+ if (m_hiden) {
+ m_clock_sr = 0;
+ m_data_sr = ~0;
+ } else {
+ m_clock_sr = ~0;
+ m_data_sr = 0;
}
- // When shifting is done DSR is filled with 1s and CSR with 0s
}
- if (BIT(m_cntl_reg , REG_CNTL_READON_BIT)) {
- // Reading
- m_pll.ctime = sdok_time;
-
- for (unsigned i = 0; i < 8; i++) {
- read_bit(do_crc_upd);
- }
- LOG_0(("RD D=%02x/C=%02x\n" , m_data_sr , m_clock_sr));
- }
- LOG_0(("next SDOK @ %.06f\n" , m_pll.ctime.as_double()));
- timer.adjust(m_pll.ctime - sdok_time);
}
- break;
-
- case HALF_BIT_TMR_ID:
- {
- m_pll.ctime = machine().time();
- if (m_lckup) {
- // Trying to lock on synchronization bytes
- attotime edge;
- attotime tm;
- get_next_transition(m_pll.ctime, edge);
- bool half_bit0 = m_pll.feed_read_data(tm , edge , attotime::never);
- get_next_transition(m_pll.ctime, edge);
- bool half_bit1 = m_pll.feed_read_data(tm , edge , attotime::never);
- if (half_bit0 == half_bit1) {
- // If half bits are equal, no synch
- LOG_0(("Reset sync_cnt\n"));
- m_sync_cnt = 0;
- } else if (++m_sync_cnt >= MIN_SYNC_BITS) {
- // Synchronized, now wait for AM
- LOG_0(("Synchronized @ %.6f\n" , machine().time().as_double()));
- m_lckup = false;
- if (BIT(m_cntl_reg , REG_CNTL_WRITON_BIT)) {
- // When loopback is active, leave AM detection to byte timer as
- // byte boundary is already synchronized
- timer.reset();
- return;
- } else {
- // Align with bit cell
- // Synchronization bits in HP mode: 32x 1s -> C/D bits = 01010101...
- // Synchronization bits in IBM mode: 32x 0s -> C/D bits = 10101010...
- if (m_hiden != half_bit1) {
- // Discard 1/2 bit cell if synchronization achieved in the clock part
- get_next_transition(m_pll.ctime, edge);
- m_pll.feed_read_data(tm , edge , attotime::never);
- }
- // Load CSR & DSR as they are after synchronization bits
- if (m_hiden) {
- m_clock_sr = 0;
- m_data_sr = ~0;
- } else {
- m_clock_sr = ~0;
- m_data_sr = 0;
- }
- }
- }
- } else {
- // Looking for AM
- /// CRC is not updated because it can't be possibly enabled at this point
+ } else {
+ // Looking for AM
+ /// CRC is not updated because it can't be possibly enabled at this point
+ read_bit(false);
+ if ((m_hiden && !BIT(m_data_sr , 7)) ||
+ (!m_hiden && BIT(m_data_sr , 0))) {
+ // Got AM as soon as bits being shifted into DSR change value wrt synchronization bits
+ m_amdt = true;
+ // Finish the current byte
+ for (unsigned i = 0; i < 7; i++) {
read_bit(false);
- if ((m_hiden && !BIT(m_data_sr , 7)) ||
- (!m_hiden && BIT(m_data_sr , 0))) {
- // Got AM as soon as bits being shifted into DSR change value wrt synchronization bits
- m_amdt = true;
- // Finish the current byte
- for (unsigned i = 0; i < 7; i++) {
- read_bit(false);
- }
- attotime adjust{m_pll.ctime - machine().time()};
- LOG_0(("Got AM @ %.6f, ctime=%.6f, adj=%.6f, D=%02x/C=%02x\n" , machine().time().as_double() , m_pll.ctime.as_double() , adjust.as_double() , m_data_sr , m_clock_sr));
- // Disable half-bit timer & enable byte timer
- timer.reset();
- m_byte_timer->adjust(adjust);
- return;
- }
}
- timer.adjust(m_pll.ctime - machine().time());
+ attotime adjust{m_pll.ctime - machine().time()};
+ LOGMASKED(LOG_LEVEL0, "Got AM @ %.6f, ctime=%.6f, adj=%.6f, D=%02x/C=%02x\n" , machine().time().as_double() , m_pll.ctime.as_double() , adjust.as_double() , m_data_sr , m_clock_sr);
+ // Disable half-bit timer & enable byte timer
+ m_half_bit_timer->reset();
+ m_byte_timer->adjust(adjust);
+ return;
}
- break;
-
- default:
- break;
}
+ m_half_bit_timer->adjust(m_pll.ctime - machine().time());
}
void hp9895_device::ieee488_eoi(int state)
@@ -431,42 +416,42 @@ void hp9895_device::ieee488_ren(int state)
m_phi->ren_w(state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_eoi_w)
+void hp9895_device::phi_eoi_w(int state)
{
m_bus->eoi_w(this , state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_dav_w)
+void hp9895_device::phi_dav_w(int state)
{
m_bus->dav_w(this , state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_nrfd_w)
+void hp9895_device::phi_nrfd_w(int state)
{
m_bus->nrfd_w(this , state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_ndac_w)
+void hp9895_device::phi_ndac_w(int state)
{
m_bus->ndac_w(this , state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_ifc_w)
+void hp9895_device::phi_ifc_w(int state)
{
m_bus->ifc_w(this , state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_srq_w)
+void hp9895_device::phi_srq_w(int state)
{
m_bus->srq_w(this , state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_atn_w)
+void hp9895_device::phi_atn_w(int state)
{
m_bus->atn_w(this , state);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_ren_w)
+void hp9895_device::phi_ren_w(int state)
{
m_bus->ren_w(this , state);
}
@@ -481,7 +466,7 @@ void hp9895_device::phi_dio_w(uint8_t data)
m_bus->dio_w(this , data);
}
-WRITE_LINE_MEMBER(hp9895_device::phi_int_w)
+void hp9895_device::phi_int_w(int state)
{
m_cpu->set_input_line(INPUT_LINE_NMI , state);
if (state) {
@@ -514,7 +499,7 @@ void hp9895_device::z80_m1_w(uint8_t data)
void hp9895_device::data_w(uint8_t data)
{
- LOG_0(("W DATA=%02x\n" , data));
+ LOGMASKED(LOG_LEVEL0, "W DATA=%02x\n" , data);
// CPU stalls until next SDOK
m_cpu->suspend_until_trigger(1 , true);
m_data_sr = data;
@@ -524,13 +509,13 @@ void hp9895_device::data_w(uint8_t data)
void hp9895_device::clock_w(uint8_t data)
{
- LOG_0(("W CLOCK=%02x\n" , data));
+ LOGMASKED(LOG_LEVEL0, "W CLOCK=%02x\n" , data);
m_clock_reg = data;
}
void hp9895_device::reset_w(uint8_t data)
{
- LOG_0(("W RESET=%02x\n" , data));
+ LOGMASKED(LOG_LEVEL0, "W RESET=%02x\n" , data);
if (BIT(data , REG_RESET_TIMEOUT_START_BIT)) {
m_timeout = false;
m_timeout_timer->adjust(attotime::from_msec(TIMEOUT_MSEC));
@@ -543,14 +528,14 @@ void hp9895_device::reset_w(uint8_t data)
void hp9895_device::leds_w(uint8_t data)
{
- LOG(("W LEDS=%02x %c%c%c%c%c\n" , data , BIT(data , 4) ? '.' : '*' , BIT(data , 3) ? '.' : '*' , BIT(data , 2) ? '.' : '*' , BIT(data , 1) ? '.' : '*' , BIT(data , 0) ? '.' : '*'));
+ LOGMASKED(LOG_LEVEL1, "W LEDS=%02x %c%c%c%c%c\n" , data , BIT(data , 4) ? '.' : '*' , BIT(data , 3) ? '.' : '*' , BIT(data , 2) ? '.' : '*' , BIT(data , 1) ? '.' : '*' , BIT(data , 0) ? '.' : '*');
// TODO:
}
void hp9895_device::cntl_w(uint8_t data)
{
if (data != m_cntl_reg) {
- LOG_0(("W CNTL=%02x -> %02x\n" , m_cntl_reg , data));
+ LOGMASKED(LOG_LEVEL0, "W CNTL=%02x -> %02x\n" , m_cntl_reg , data);
uint8_t old_cntl_reg = m_cntl_reg;
m_cntl_reg = data;
@@ -563,11 +548,11 @@ void hp9895_device::cntl_w(uint8_t data)
bool byte_timer_needed = new_writon || (new_readon && m_amdt);
if (!byte_timer_running && byte_timer_needed) {
- LOG_0(("Enable byte tmr\n"));
+ LOGMASKED(LOG_LEVEL0, "Enable byte tmr\n");
attotime byte_period = get_half_bit_cell_period() * 16;
m_byte_timer->adjust(byte_period);
} else if (byte_timer_running && !byte_timer_needed) {
- LOG_0(("Disable byte tmr\n"));
+ LOGMASKED(LOG_LEVEL0, "Disable byte tmr\n");
m_byte_timer->reset();
}
@@ -577,24 +562,24 @@ void hp9895_device::cntl_w(uint8_t data)
if (!old_writon && new_writon) {
// Writing enabled
- LOG_0(("Start writing..\n"));
+ LOGMASKED(LOG_LEVEL0, "Start writing\n");
m_pll.start_writing(machine().time());
m_wr_context = 0;
m_had_transition = false;
} else if (old_writon && !new_writon) {
// Writing disabled
- LOG_0(("Stop writing..\n"));
+ LOGMASKED(LOG_LEVEL0, "Stop writing\n");
m_pll.stop_writing(get_write_device() , machine().time());
}
if (!old_readon && new_readon) {
// Reading enabled
- LOG_0(("Start reading..\n"));
+ LOGMASKED(LOG_LEVEL0, "Start reading\n");
m_pll.read_reset(machine().time());
m_sync_cnt = 0;
m_half_bit_timer->adjust(get_half_bit_cell_period());
} else if (old_readon && !new_readon) {
// Reading disabled
- LOG_0(("Stop reading..\n"));
+ LOGMASKED(LOG_LEVEL0, "Stop reading\n");
m_half_bit_timer->reset();
m_lckup = true;
m_amdt = false;
@@ -610,7 +595,7 @@ void hp9895_device::cntl_w(uint8_t data)
void hp9895_device::drv_w(uint8_t data)
{
- LOG_0(("W DRV=%02x\n" , data));
+ LOGMASKED(LOG_LEVEL0, "W DRV=%02x\n" , data);
m_mgnena = BIT(data , REG_DRV_MGNENA_BIT);
if (m_current_drive != nullptr) {
m_current_drive->stp_w(!BIT(data , REG_DRV_STEP_BIT));
@@ -622,11 +607,11 @@ void hp9895_device::drv_w(uint8_t data)
void hp9895_device::xv_w(uint8_t data)
{
- LOG_0(("W XV=%02x\n" , data));
+ LOGMASKED(LOG_LEVEL0, "W XV=%02x\n" , data);
// Disk Changed flag is cleared when drive is ready and it is deselected
if (m_current_drive_idx < 2 && (data & xv_drive_masks[ m_current_drive_idx ]) == 0 && !m_current_drive->ready_r()) {
if (m_dskchg[ m_current_drive_idx ]) {
- LOG(("Dskchg %u cleared\n" , m_current_drive_idx));
+ LOGMASKED(LOG_LEVEL1, "Dskchg %u cleared\n" , m_current_drive_idx);
}
m_dskchg[ m_current_drive_idx ] = false;
}
@@ -648,7 +633,7 @@ uint8_t hp9895_device::data_r()
{
m_clock_reg = m_clock_sr;
m_accdata = true;
- LOG_0(("R DATA=%02x\n" , m_data_sr));
+ LOGMASKED(LOG_LEVEL0, "R DATA=%02x\n" , m_data_sr);
// CPU stalls until next SDOK
m_cpu->suspend_until_trigger(1 , true);
return m_data_sr;
@@ -689,7 +674,7 @@ uint8_t hp9895_device::drivstat_r()
if (m_overrun) {
BIT_SET(res , REG_DRIVSTAT_OVERUN_BIT);
}
- LOG_0(("R DRIVSTAT=%02x\n" , res));
+ LOGMASKED(LOG_LEVEL0, "R DRIVSTAT=%02x\n" , res);
return res;
}
@@ -711,7 +696,7 @@ void hp9895_device::floppy_ready_cb(floppy_image_device *floppy , int state)
// Set Disk Changed flag when a drive is not ready
for (unsigned i = 0; i < 2; i++) {
if (floppy == m_drives[ i ]->get_device()) {
- LOG(("Dskchg %u set\n" , i));
+ LOGMASKED(LOG_LEVEL1, "Dskchg %u set\n" , i);
m_dskchg[ i ] = true;
break;
}
@@ -877,6 +862,8 @@ static void hp9895_floppies(device_slot_interface &device)
static void hp9895_floppy_formats(format_registration &fr)
{
fr.add(FLOPPY_HPI_FORMAT);
+ fr.add(fs::HP9825);
+ fr.add(fs::HP9845);
};
const tiny_rom_entry *hp9895_device::device_rom_region() const