mirror of
https://github.com/holub/mame
synced 2025-04-23 08:49:55 +03:00
commit
5b0d4772a3
@ -2,12 +2,55 @@
|
||||
// copyright-holders: F. Ulivi
|
||||
/*********************************************************************
|
||||
|
||||
hp9895.cpp
|
||||
hp9895.cpp
|
||||
|
||||
HP9895 floppy disk drive
|
||||
HP9895 floppy disk drive
|
||||
|
||||
Reference manual:
|
||||
HP 09895-90030, feb 81, 9895A Flexible Disc Memory Service Manual
|
||||
Phew, this one was tough!
|
||||
|
||||
This is a dual 8" floppy disk drive that interfaces through
|
||||
HPIB/IEEE-488 bus. It implements the so-called "Amigo" command
|
||||
set.
|
||||
|
||||
Its main components are:
|
||||
* A Z80A CPU @ 4 MHz with 8 kB of firmware ROM and 1 kB of
|
||||
static RAM
|
||||
* A HP PHI chip that interfaces CPU to HPIB bus
|
||||
* A disk controller implemented with a lot of discrete TTLs
|
||||
* 2 MPI 8" disk drives
|
||||
|
||||
Data I/O with the disk is carried out through 2 shift registers,
|
||||
one for data bits (@ 0x60 address) and one for clock bits (@ 0x61
|
||||
address). CPU is stalled by setting WAIT/ to 0 whenever it accesses
|
||||
the data register and the hw is not ready for the byte. Once
|
||||
the next byte boundary is reached (the SDOK signal activates) the
|
||||
CPU is released and either the data byte is read from shift register
|
||||
or written into it. At the same time clock shift register is
|
||||
copied into clock register when reading or viceversa when writing.
|
||||
|
||||
The 9895 drive can operate in 2 modes: HP/High density or IBM/low
|
||||
density. This table summarizes the differences between the modes.
|
||||
See also page 2-12 of service manual.
|
||||
|
||||
| Characteristic | HP mode | IBM mode |
|
||||
|----------------+----------+-----------|
|
||||
| Bit cell size | 2 µs | 4 µs |
|
||||
| Modulation | MMFM | FM |
|
||||
| Bit order | LS first | MS first |
|
||||
| Sync bytes | 4x FF | 6x 00 |
|
||||
| Formatted size | 1155 kB | 250.25 kB |
|
||||
|
||||
Reference manual:
|
||||
HP 09895-90030, feb 81, 9895A Flexible Disc Memory Service Manual
|
||||
|
||||
Reference manual for the floppy drives:
|
||||
Magnetic Peripherals, inc., feb 83, 9406-4 Flexible Disk Drive
|
||||
Hardware Maintenance Manual
|
||||
|
||||
TODO/Issues:
|
||||
* floppy_image_device sometimes reports the wrong state for ready &
|
||||
wpt signals
|
||||
* IBM mode hasn't been tested yet
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
@ -16,31 +59,338 @@
|
||||
// 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)
|
||||
|
||||
// Macros to clear/set single bits
|
||||
#define BIT_MASK(n) (1U << (n))
|
||||
#define BIT_CLR(w , n) ((w) &= ~BIT_MASK(n))
|
||||
#define BIT_SET(w , n) ((w) |= BIT_MASK(n))
|
||||
|
||||
// Bits in RESET register
|
||||
#define REG_RESET_TIMEOUT_START_BIT 0 // Start TIMEOUT oneshot (1)
|
||||
#define REG_RESET_OVERUN_CLEAR_BIT 1 // Clear OVERUN (sic) (1)
|
||||
#define REG_RESET_PROGRES_BIT 3 // PROGRES (1)
|
||||
|
||||
// Bits in CNTL register
|
||||
#define REG_CNTL_READON_BIT 1 // Enable reading (1)
|
||||
#define REG_CNTL_WRITON_BIT 2 // Enable writing (1)
|
||||
#define REG_CNTL_WRITDRV_BIT 3 // Enable writing to floppy (1)
|
||||
#define REG_CNTL_CRCOUT_BIT 4 // Enable output of CRC word (1)
|
||||
#define REG_CNTL_CRCON_BIT 5 // Enable updating of CRC word (1) or preset CRC to 0xffff (0)
|
||||
|
||||
// Bits in DRV register
|
||||
#define REG_DRV_STEP_BIT 0 // Step pulse to drive (1)
|
||||
#define REG_DRV_MOVEIN_BIT 1 // Move heads inward (1)
|
||||
#define REG_DRV_MGNENA_BIT 2 // Enable checking of bit cell margins (1)
|
||||
#define REG_DRV_IN_USE_BIT 3 // "In use" signal to drive (1)
|
||||
#define REG_DRV_LOWCURR_BIT 4 // Reduce write current in inner tracks (1)
|
||||
#define REG_DRV_HEADSEL_BIT 7 // Head selection (1 = Head 1)
|
||||
|
||||
// Bits in XV register
|
||||
#define REG_XV_DRIVE3_BIT 0 // Select drive #3 (1)
|
||||
#define REG_XV_DRIVE2_BIT 1 // Select drive #2 (1)
|
||||
#define REG_XV_DRIVE1_BIT 2 // Select drive #1 (1)
|
||||
#define REG_XV_DRIVE0_BIT 3 // Select drive #0 (1)
|
||||
#define REG_XV_HIDEN_BIT 4 // Select HP/High density mode (1) or IBM/Low density mode (0)
|
||||
#define REG_XV_PRECMP_BIT 5 // Enable pre-compensation
|
||||
|
||||
// Bits in DRIVSTAT register
|
||||
#define REG_DRIVSTAT_INDEX_BIT 0 // Index pulse from drive (1)
|
||||
#define REG_DRIVSTAT_DISCHNG_BIT 1 // Disk changed (1)
|
||||
#define REG_DRIVSTAT_TRACK0_BIT 2 // Heads on track #0 (1)
|
||||
#define REG_DRIVSTAT_WRPROT_BIT 3 // Disk is write-protected (1)
|
||||
#define REG_DRIVSTAT_READY_BIT 4 // Disk is ready (1)
|
||||
#define REG_DRIVSTAT_CRCERR_BIT 5 // Error in CRC (1)
|
||||
#define REG_DRIVSTAT_OVERUN_BIT 6 // I/O overrun between disk and CPU (1)
|
||||
#define REG_DRIVSTAT_TWOSIDE_BIT 7 // 2-sided disk (1)
|
||||
|
||||
// Bits in SWITCHES(2) registers
|
||||
#define REG_SWITCHES_HPIB_ADDR_SHIFT 0 // LSB of HPIB address
|
||||
#define REG_SWITCHES_HPIB_ADDR_MASK 7 // Mask of HPIB address
|
||||
#define REG_SWITCHES_W_TEST_BIT 3 // "W" test push-button (1)
|
||||
#define REG_SWITCHES_S_TEST_BIT 4 // "S" test push-button (1)
|
||||
#define REG_SWITCHES_LOOP_BIT 5 // Test loop option (1)
|
||||
#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)
|
||||
#define IBMMODE_BIT_FREQ 250000 // IBM-mode bit frequency (Hz)
|
||||
|
||||
#define MIN_SYNC_BITS 29 // Number of bits to synchronize
|
||||
|
||||
// device type definition
|
||||
const device_type HP9895 = &device_creator<hp9895_device>;
|
||||
|
||||
// Masks of drive selectors in XV register
|
||||
static const uint8_t xv_drive_masks[] = {
|
||||
BIT_MASK(REG_XV_DRIVE0_BIT),
|
||||
BIT_MASK(REG_XV_DRIVE1_BIT)
|
||||
};
|
||||
|
||||
hp9895_device::hp9895_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, HP9895, "HP9895", tag, owner, clock, "HP9895", __FILE__),
|
||||
device_ieee488_interface(mconfig, *this),
|
||||
m_cpu(*this , "cpu"),
|
||||
m_phi(*this , "phi")
|
||||
m_phi(*this , "phi"),
|
||||
m_drives{{*this , "floppy0"} , {*this , "floppy1"}},
|
||||
m_switches{*this , "switches"}
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
static INPUT_PORTS_START(hp9895_port)
|
||||
PORT_START("switches")
|
||||
PORT_CONFNAME(REG_SWITCHES_HPIB_ADDR_MASK << REG_SWITCHES_HPIB_ADDR_SHIFT , 0x00 , "HPIB address")
|
||||
PORT_CONFSETTING(0 << REG_SWITCHES_HPIB_ADDR_SHIFT , "0")
|
||||
PORT_CONFSETTING(1 << REG_SWITCHES_HPIB_ADDR_SHIFT , "1")
|
||||
PORT_CONFSETTING(2 << REG_SWITCHES_HPIB_ADDR_SHIFT , "2")
|
||||
PORT_CONFSETTING(3 << REG_SWITCHES_HPIB_ADDR_SHIFT , "3")
|
||||
PORT_CONFSETTING(4 << REG_SWITCHES_HPIB_ADDR_SHIFT , "4")
|
||||
PORT_CONFSETTING(5 << REG_SWITCHES_HPIB_ADDR_SHIFT , "5")
|
||||
PORT_CONFSETTING(6 << REG_SWITCHES_HPIB_ADDR_SHIFT , "6")
|
||||
PORT_CONFSETTING(7 << REG_SWITCHES_HPIB_ADDR_SHIFT , "7")
|
||||
PORT_CONFNAME(BIT_MASK(REG_SWITCHES_W_TEST_BIT) , 0x00 , "W Test")
|
||||
PORT_CONFSETTING(0x00 , DEF_STR(Off))
|
||||
PORT_CONFSETTING(BIT_MASK(REG_SWITCHES_W_TEST_BIT) , DEF_STR(On))
|
||||
PORT_CONFNAME(BIT_MASK(REG_SWITCHES_S_TEST_BIT) , 0x00 , "S Test")
|
||||
PORT_CONFSETTING(0x00 , DEF_STR(Off))
|
||||
PORT_CONFSETTING(BIT_MASK(REG_SWITCHES_S_TEST_BIT) , DEF_STR(On))
|
||||
PORT_CONFNAME(BIT_MASK(REG_SWITCHES_LOOP_BIT) , 0x00 , "Loop")
|
||||
PORT_CONFSETTING(0x00 , DEF_STR(Off))
|
||||
PORT_CONFSETTING(BIT_MASK(REG_SWITCHES_LOOP_BIT) , DEF_STR(On))
|
||||
INPUT_PORTS_END
|
||||
|
||||
ioport_constructor hp9895_device::device_input_ports() const
|
||||
{
|
||||
// TODO: inputs=HPIB address, "S" & "W" switches, "loop" pin
|
||||
return INPUT_PORTS_NAME(hp9895_port);
|
||||
}
|
||||
#endif
|
||||
|
||||
void hp9895_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_cpu_irq));
|
||||
save_item(NAME(m_current_drive_idx));
|
||||
save_item(NAME(m_dskchg));
|
||||
save_item(NAME(m_crc));
|
||||
save_item(NAME(m_crcerr_syn));
|
||||
save_item(NAME(m_overrun));
|
||||
save_item(NAME(m_accdata));
|
||||
save_item(NAME(m_timeout));
|
||||
save_item(NAME(m_cntl_reg));
|
||||
save_item(NAME(m_clock_sr));
|
||||
save_item(NAME(m_clock_reg));
|
||||
save_item(NAME(m_data_sr));
|
||||
save_item(NAME(m_wr_context));
|
||||
save_item(NAME(m_had_transition));
|
||||
save_item(NAME(m_lckup));
|
||||
save_item(NAME(m_amdt));
|
||||
save_item(NAME(m_sync_cnt));
|
||||
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);
|
||||
|
||||
for (auto& d : m_drives) {
|
||||
d->get_device()->setup_ready_cb(floppy_image_device::ready_cb(&hp9895_device::floppy_ready_cb , this));
|
||||
}
|
||||
}
|
||||
|
||||
void hp9895_device::device_reset()
|
||||
{
|
||||
m_cpu_irq = false;
|
||||
m_current_drive = nullptr;
|
||||
m_current_drive_idx = ~0;
|
||||
for (auto& d : m_dskchg) {
|
||||
d = true;
|
||||
}
|
||||
preset_crc();
|
||||
m_crcerr_syn = false;
|
||||
m_overrun = false;
|
||||
m_accdata = false;
|
||||
m_timeout = true;
|
||||
m_cntl_reg = 0;
|
||||
m_clock_sr = 0;
|
||||
m_clock_reg = 0;
|
||||
m_data_sr = 0;
|
||||
m_wr_context = 0;
|
||||
m_had_transition = false;
|
||||
m_lckup = true; // Because READON = 0
|
||||
m_amdt = false;
|
||||
m_sync_cnt = 0;
|
||||
m_hiden = false;
|
||||
m_mgnena = false;
|
||||
m_timeout_timer->reset();
|
||||
m_byte_timer->reset();
|
||||
m_half_bit_timer->reset();
|
||||
#if 0
|
||||
// DEBUG DEBUG DEBUG DEBUG
|
||||
for (auto& r : m_ready) r = 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
void hp9895_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
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;
|
||||
|
||||
case BYTE_TMR_ID:
|
||||
{
|
||||
if (m_accdata) {
|
||||
// Resume CPU when it's waiting for SDOK
|
||||
m_cpu->trigger(1);
|
||||
} else {
|
||||
// No access to data register by CPU
|
||||
LOG(("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()};
|
||||
LOG_0(("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 {
|
||||
m_amdt = m_data_sr != 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// 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
|
||||
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());
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hp9895_device::ieee488_eoi(int state)
|
||||
@ -160,6 +510,349 @@ WRITE16_MEMBER(hp9895_device::z80_m1_w)
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(hp9895_device::data_w)
|
||||
{
|
||||
LOG_0(("W DATA=%02x\n" , data));
|
||||
// CPU stalls until next SDOK
|
||||
m_cpu->suspend_until_trigger(1 , true);
|
||||
m_data_sr = data;
|
||||
m_clock_sr = m_clock_reg;
|
||||
m_accdata = true;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(hp9895_device::clock_w)
|
||||
{
|
||||
LOG_0(("W CLOCK=%02x\n" , data));
|
||||
m_clock_reg = data;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(hp9895_device::reset_w)
|
||||
{
|
||||
LOG_0(("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));
|
||||
}
|
||||
if (BIT(data , REG_RESET_OVERUN_CLEAR_BIT)) {
|
||||
m_overrun = false;
|
||||
}
|
||||
// TODO: PROGRES
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(hp9895_device::leds_w)
|
||||
{
|
||||
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) ? '.' : '*'));
|
||||
// TODO:
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(hp9895_device::cntl_w)
|
||||
{
|
||||
if (data != m_cntl_reg) {
|
||||
LOG_0(("W CNTL=%02x -> %02x\n" , m_cntl_reg , data));
|
||||
uint8_t old_cntl_reg = m_cntl_reg;
|
||||
m_cntl_reg = data;
|
||||
|
||||
bool old_writon = BIT(old_cntl_reg , REG_CNTL_WRITON_BIT);
|
||||
bool new_writon = BIT(m_cntl_reg , REG_CNTL_WRITON_BIT);
|
||||
bool old_readon = BIT(old_cntl_reg , REG_CNTL_READON_BIT);
|
||||
bool new_readon = BIT(m_cntl_reg , REG_CNTL_READON_BIT);
|
||||
|
||||
bool byte_timer_running = old_writon || m_amdt;
|
||||
bool byte_timer_needed = new_writon || (new_readon && m_amdt);
|
||||
|
||||
if (!byte_timer_running && byte_timer_needed) {
|
||||
LOG_0(("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"));
|
||||
m_byte_timer->reset();
|
||||
}
|
||||
|
||||
if (!old_writon && !old_readon && (new_writon || new_readon)) {
|
||||
m_pll.set_clock(get_half_bit_cell_period());
|
||||
}
|
||||
|
||||
if (!old_writon && new_writon) {
|
||||
// Writing enabled
|
||||
LOG_0(("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"));
|
||||
m_pll.stop_writing(get_write_device() , machine().time());
|
||||
}
|
||||
if (!old_readon && new_readon) {
|
||||
// Reading enabled
|
||||
LOG_0(("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"));
|
||||
m_half_bit_timer->reset();
|
||||
m_lckup = true;
|
||||
m_amdt = false;
|
||||
}
|
||||
if (!new_readon && !new_writon) {
|
||||
m_crcerr_syn = false;
|
||||
BIT_CLR(m_cntl_reg, REG_CNTL_CRCON_BIT);
|
||||
BIT_CLR(m_cntl_reg, REG_CNTL_CRCOUT_BIT);
|
||||
preset_crc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(hp9895_device::drv_w)
|
||||
{
|
||||
LOG_0(("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));
|
||||
m_current_drive->dir_w(!BIT(data , REG_DRV_MOVEIN_BIT));
|
||||
// TODO: in use signal
|
||||
m_current_drive->ss_w(BIT(data , REG_DRV_HEADSEL_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(hp9895_device::xv_w)
|
||||
{
|
||||
LOG_0(("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));
|
||||
}
|
||||
m_dskchg[ m_current_drive_idx ] = false;
|
||||
}
|
||||
|
||||
m_current_drive = nullptr;
|
||||
m_current_drive_idx = ~0;
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
if (data & xv_drive_masks[ i ]) {
|
||||
m_current_drive = m_drives[ i ]->get_device();
|
||||
m_current_drive_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_hiden = BIT(data , REG_XV_HIDEN_BIT);
|
||||
}
|
||||
|
||||
READ8_MEMBER(hp9895_device::data_r)
|
||||
{
|
||||
m_clock_reg = m_clock_sr;
|
||||
m_accdata = true;
|
||||
LOG_0(("R DATA=%02x\n" , m_data_sr));
|
||||
// CPU stalls until next SDOK
|
||||
m_cpu->suspend_until_trigger(1 , true);
|
||||
return m_data_sr;
|
||||
}
|
||||
|
||||
READ8_MEMBER(hp9895_device::clock_r)
|
||||
{
|
||||
return m_clock_reg;
|
||||
}
|
||||
|
||||
READ8_MEMBER(hp9895_device::drivstat_r)
|
||||
{
|
||||
uint8_t res = 0;
|
||||
|
||||
if (m_current_drive != nullptr) {
|
||||
if (m_current_drive->idx_r()) {
|
||||
BIT_SET(res , REG_DRIVSTAT_INDEX_BIT);
|
||||
}
|
||||
if (m_dskchg[ m_current_drive_idx ]) {
|
||||
BIT_SET(res , REG_DRIVSTAT_DISCHNG_BIT);
|
||||
}
|
||||
if (!m_current_drive->trk00_r()) {
|
||||
BIT_SET(res , REG_DRIVSTAT_TRACK0_BIT);
|
||||
}
|
||||
if (m_current_drive->wpt_r()) {
|
||||
BIT_SET(res , REG_DRIVSTAT_WRPROT_BIT);
|
||||
}
|
||||
if (!m_current_drive->ready_r()) {
|
||||
BIT_SET(res , REG_DRIVSTAT_READY_BIT);
|
||||
}
|
||||
if (!m_current_drive->twosid_r()) {
|
||||
BIT_SET(res , REG_DRIVSTAT_TWOSIDE_BIT);
|
||||
}
|
||||
}
|
||||
if (m_crcerr_syn) {
|
||||
BIT_SET(res , REG_DRIVSTAT_CRCERR_BIT);
|
||||
}
|
||||
if (m_overrun) {
|
||||
BIT_SET(res , REG_DRIVSTAT_OVERUN_BIT);
|
||||
}
|
||||
LOG_0(("R DRIVSTAT=%02x\n" , res));
|
||||
return res;
|
||||
}
|
||||
|
||||
READ8_MEMBER(hp9895_device::switches_r)
|
||||
{
|
||||
uint8_t res = get_switches2();
|
||||
res |= m_switches->read();
|
||||
return res;
|
||||
}
|
||||
|
||||
READ8_MEMBER(hp9895_device::switches2_r)
|
||||
{
|
||||
return get_switches2();
|
||||
}
|
||||
|
||||
void hp9895_device::floppy_ready_cb(floppy_image_device *floppy , int state)
|
||||
{
|
||||
#if 0
|
||||
// DEBUG DEBUG DEBUG DEBUG
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
if (floppy == m_drives[ i ]->get_device()) {
|
||||
if (m_ready[ i ] != state) {
|
||||
LOG(("Ready %u=%d\n" , i , state));
|
||||
m_ready[ i ] = state;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (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));
|
||||
m_dskchg[ i ] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t hp9895_device::get_switches2(void) const
|
||||
{
|
||||
uint8_t res = 0;
|
||||
|
||||
if (m_timeout) {
|
||||
BIT_SET(res, REG_SWITCHES_TIMEOUT_BIT);
|
||||
}
|
||||
if (m_amdt) {
|
||||
BIT_SET(res, REG_SWITCHES_AMDT_BIT);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
attotime hp9895_device::get_half_bit_cell_period(void) const
|
||||
{
|
||||
return attotime::from_hz((m_hiden ? HPMODE_BIT_FREQ : IBMMODE_BIT_FREQ) * 2);
|
||||
}
|
||||
|
||||
floppy_image_device *hp9895_device::get_write_device(void) const
|
||||
{
|
||||
if (!BIT(m_cntl_reg , REG_CNTL_WRITDRV_BIT)) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return m_current_drive;
|
||||
}
|
||||
}
|
||||
|
||||
void hp9895_device::preset_crc(void)
|
||||
{
|
||||
m_crc = ~0;
|
||||
}
|
||||
|
||||
void hp9895_device::update_crc(bool bit)
|
||||
{
|
||||
bool msb = BIT(m_crc , 15);
|
||||
|
||||
m_crc <<= 1;
|
||||
if (bit ^ msb) {
|
||||
m_crc ^= 0x1021;
|
||||
}
|
||||
}
|
||||
|
||||
bool hp9895_device::shift_sr(uint8_t& sr , bool input_bit)
|
||||
{
|
||||
bool res;
|
||||
|
||||
if (m_hiden) {
|
||||
res = BIT(sr , 0);
|
||||
sr >>= 1;
|
||||
if (input_bit) {
|
||||
BIT_SET(sr , 7);
|
||||
}
|
||||
} else {
|
||||
res = BIT(sr , 7);
|
||||
sr <<= 1;
|
||||
if (input_bit) {
|
||||
BIT_SET(sr , 0);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void hp9895_device::get_next_transition(const attotime& from_when , attotime& edge)
|
||||
{
|
||||
edge = attotime::never;
|
||||
|
||||
if (BIT(m_cntl_reg , REG_CNTL_WRITON_BIT)) {
|
||||
// Loop back write transitions into reading data path
|
||||
for (int idx = 0; idx < m_pll.write_position; idx++) {
|
||||
if (m_pll.write_buffer[ idx ] >= from_when) {
|
||||
edge = m_pll.write_buffer[ idx ];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (m_current_drive != nullptr) {
|
||||
edge = m_current_drive->get_next_transition(from_when);
|
||||
}
|
||||
}
|
||||
|
||||
void hp9895_device::read_bit(bool crc_upd)
|
||||
{
|
||||
attotime edge;
|
||||
attotime tm;
|
||||
|
||||
get_next_transition(m_pll.ctime, edge);
|
||||
bool clock_bit = m_pll.feed_read_data(tm , edge , attotime::never);
|
||||
get_next_transition(m_pll.ctime, edge);
|
||||
bool data_bit = m_pll.feed_read_data(tm , edge , attotime::never);
|
||||
|
||||
shift_sr(m_clock_sr, clock_bit);
|
||||
data_bit = shift_sr(m_data_sr, data_bit);
|
||||
|
||||
if (crc_upd &&
|
||||
BIT(m_cntl_reg , REG_CNTL_CRCON_BIT) &&
|
||||
!BIT(m_cntl_reg , REG_CNTL_CRCOUT_BIT)) {
|
||||
update_crc(data_bit);
|
||||
}
|
||||
}
|
||||
|
||||
void hp9895_device::write_bit(bool data_bit , bool clock_bit)
|
||||
{
|
||||
if (m_hiden) {
|
||||
// **** HP mode ****
|
||||
// m_wr_context delays data bits by 2 bit cells
|
||||
// Bit Content
|
||||
// ============
|
||||
// 2 Data @ t-2
|
||||
// 1 Data @ t-1
|
||||
// 0 Data @ t
|
||||
m_wr_context = (m_wr_context << 1) | data_bit;
|
||||
data_bit = BIT(m_wr_context , 2);
|
||||
clock_bit = !data_bit && (clock_bit || !m_had_transition);
|
||||
m_had_transition = data_bit || clock_bit;
|
||||
}
|
||||
// else... IBM mode, nothing to do
|
||||
|
||||
attotime dummy;
|
||||
|
||||
m_pll.write_next_bit(clock_bit , dummy , nullptr , attotime::never);
|
||||
m_pll.write_next_bit(data_bit , dummy , nullptr , attotime::never);
|
||||
}
|
||||
|
||||
ROM_START(hp9895)
|
||||
ROM_REGION(0x2000 , "cpu" , 0)
|
||||
ROM_LOAD("1818-1391a.bin" , 0 , 0x2000 , CRC(b50dbfb5) SHA1(96edf9af78be75fbad2a0245b8af43958ba32752))
|
||||
@ -175,9 +868,20 @@ static ADDRESS_MAP_START(z80_io_map , AS_IO , 8 , hp9895_device)
|
||||
ADDRESS_MAP_UNMAP_HIGH
|
||||
ADDRESS_MAP_GLOBAL_MASK(0xff)
|
||||
AM_RANGE(0x10 , 0x17) AM_DEVWRITE("phi" , phi_device , reg8_w) AM_READ(phi_reg_r)
|
||||
// TODO: 60-67 range
|
||||
AM_RANGE(0x60 , 0x60) AM_READWRITE(data_r , data_w)
|
||||
AM_RANGE(0x61 , 0x61) AM_READWRITE(clock_r , clock_w)
|
||||
AM_RANGE(0x62 , 0x62) AM_READWRITE(drivstat_r , reset_w)
|
||||
AM_RANGE(0x63 , 0x63) AM_READWRITE(switches_r , leds_w)
|
||||
AM_RANGE(0x64 , 0x64) AM_WRITE(cntl_w)
|
||||
AM_RANGE(0x65 , 0x65) AM_WRITE(drv_w)
|
||||
AM_RANGE(0x66 , 0x66) AM_WRITE(xv_w)
|
||||
AM_RANGE(0x67 , 0x67) AM_READ(switches2_r)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static SLOT_INTERFACE_START(hp9895_floppies)
|
||||
SLOT_INTERFACE("8dsdd" , FLOPPY_8_DSDD)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT(hp9895)
|
||||
MCFG_CPU_ADD("cpu" , Z80 , 4000000)
|
||||
MCFG_CPU_PROGRAM_MAP(z80_program_map)
|
||||
@ -195,6 +899,11 @@ static MACHINE_CONFIG_FRAGMENT(hp9895)
|
||||
MCFG_PHI_REN_WRITE_CB(WRITELINE(hp9895_device , phi_ren_w))
|
||||
MCFG_PHI_DIO_READWRITE_CB(READ8(hp9895_device , phi_dio_r) , WRITE8(hp9895_device , phi_dio_w))
|
||||
MCFG_PHI_INT_WRITE_CB(WRITELINE(hp9895_device , phi_int_w))
|
||||
|
||||
MCFG_FLOPPY_DRIVE_ADD("floppy0" , hp9895_floppies , "8dsdd" , floppy_image_device::default_floppy_formats)
|
||||
MCFG_SLOT_FIXED(true)
|
||||
MCFG_FLOPPY_DRIVE_ADD("floppy1" , hp9895_floppies , "8dsdd" , floppy_image_device::default_floppy_formats)
|
||||
MCFG_SLOT_FIXED(true)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
const tiny_rom_entry *hp9895_device::device_rom_region() const
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "ieee488.h"
|
||||
#include "cpu/z80/z80.h"
|
||||
#include "machine/phi.h"
|
||||
#include "imagedev/floppy.h"
|
||||
#include "machine/fdc_pll.h"
|
||||
|
||||
class hp9895_device : public device_t,
|
||||
public device_ieee488_interface
|
||||
@ -26,9 +28,10 @@ public:
|
||||
hp9895_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
//virtual ioport_constructor device_input_ports() const override;
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||
|
||||
@ -63,11 +66,71 @@ public:
|
||||
DECLARE_READ8_MEMBER(phi_reg_r);
|
||||
DECLARE_WRITE16_MEMBER(z80_m1_w);
|
||||
|
||||
// Floppy interface
|
||||
DECLARE_WRITE8_MEMBER(data_w);
|
||||
DECLARE_WRITE8_MEMBER(clock_w);
|
||||
DECLARE_WRITE8_MEMBER(reset_w);
|
||||
DECLARE_WRITE8_MEMBER(leds_w);
|
||||
DECLARE_WRITE8_MEMBER(cntl_w);
|
||||
DECLARE_WRITE8_MEMBER(drv_w);
|
||||
DECLARE_WRITE8_MEMBER(xv_w);
|
||||
DECLARE_READ8_MEMBER(data_r);
|
||||
DECLARE_READ8_MEMBER(clock_r);
|
||||
DECLARE_READ8_MEMBER(drivstat_r);
|
||||
DECLARE_READ8_MEMBER(switches_r);
|
||||
DECLARE_READ8_MEMBER(switches2_r);
|
||||
|
||||
// Floppy drive interface
|
||||
void floppy_ready_cb(floppy_image_device *floppy , int state);
|
||||
|
||||
private:
|
||||
required_device<z80_device> m_cpu;
|
||||
required_device<phi_device> m_phi;
|
||||
required_device<floppy_connector> m_drives[ 2 ];
|
||||
required_ioport m_switches;
|
||||
|
||||
bool m_cpu_irq;
|
||||
floppy_image_device *m_current_drive;
|
||||
unsigned m_current_drive_idx;
|
||||
bool m_dskchg[ 2 ];
|
||||
uint16_t m_crc; // U77
|
||||
bool m_crcerr_syn;
|
||||
bool m_overrun;
|
||||
bool m_accdata;
|
||||
bool m_timeout;
|
||||
uint8_t m_cntl_reg; // U31
|
||||
uint8_t m_clock_sr; // U22 & U4
|
||||
uint8_t m_clock_reg; // U23 & U5
|
||||
uint8_t m_data_sr; // U24 & U6
|
||||
uint8_t m_wr_context;
|
||||
bool m_had_transition;
|
||||
bool m_lckup;
|
||||
bool m_amdt;
|
||||
uint8_t m_sync_cnt; // U28 & U73
|
||||
bool m_hiden;
|
||||
bool m_mgnena;
|
||||
#if 0
|
||||
// DEBUG DEBUG DEBUG DEBUG
|
||||
int m_ready[ 2 ];
|
||||
#endif
|
||||
|
||||
// Timers
|
||||
emu_timer *m_timeout_timer;
|
||||
emu_timer *m_byte_timer;
|
||||
emu_timer *m_half_bit_timer;
|
||||
|
||||
// PLL
|
||||
fdc_pll_t m_pll;
|
||||
|
||||
uint8_t get_switches2(void) const;
|
||||
attotime get_half_bit_cell_period(void) const;
|
||||
floppy_image_device *get_write_device(void) const;
|
||||
void preset_crc(void);
|
||||
void update_crc(bool bit);
|
||||
bool shift_sr(uint8_t& sr , bool input_bit);
|
||||
void get_next_transition(const attotime& from_when , attotime& edge);
|
||||
void read_bit(bool crc_upd);
|
||||
void write_bit(bool data_bit , bool clock_bit);
|
||||
};
|
||||
|
||||
// device type definition
|
||||
|
@ -22,12 +22,17 @@ void fdc_pll_t::set_clock(const attotime &_period)
|
||||
}
|
||||
|
||||
void fdc_pll_t::reset(const attotime &when)
|
||||
{
|
||||
read_reset(when);
|
||||
write_position = 0;
|
||||
write_start_time = attotime::never;
|
||||
}
|
||||
|
||||
void fdc_pll_t::read_reset(const attotime &when)
|
||||
{
|
||||
ctime = when;
|
||||
phase_adjust = attotime::zero;
|
||||
freq_hist = 0;
|
||||
write_position = 0;
|
||||
write_start_time = attotime::never;
|
||||
}
|
||||
|
||||
void fdc_pll_t::start_writing(const attotime &tm)
|
||||
@ -55,8 +60,13 @@ void fdc_pll_t::commit(floppy_image_device *floppy, const attotime &tm)
|
||||
|
||||
int fdc_pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit)
|
||||
{
|
||||
attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never;
|
||||
attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never;
|
||||
|
||||
return feed_read_data(tm , edge , limit);
|
||||
}
|
||||
|
||||
int fdc_pll_t::feed_read_data(attotime &tm, const attotime& edge, const attotime &limit)
|
||||
{
|
||||
attotime next = ctime + period + phase_adjust;
|
||||
|
||||
#if 0
|
||||
|
@ -21,7 +21,9 @@ public:
|
||||
|
||||
void set_clock(const attotime &period);
|
||||
void reset(const attotime &when);
|
||||
void read_reset(const attotime &when);
|
||||
int get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit);
|
||||
int feed_read_data(attotime &tm, const attotime& edge, const attotime &limit);
|
||||
bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit);
|
||||
void start_writing(const attotime &tm);
|
||||
void commit(floppy_image_device *floppy, const attotime &tm);
|
||||
|
@ -33,6 +33,8 @@
|
||||
// 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)
|
||||
|
||||
// Macros to clear/set single bits
|
||||
#define BIT_MASK(n) (1U << (n))
|
||||
@ -250,7 +252,7 @@ void phi_device::set_ext_signal(phi_488_signal_t signal , int state)
|
||||
state = !state;
|
||||
if (m_ext_signals[ signal ] != state) {
|
||||
m_ext_signals[ signal ] = state;
|
||||
LOG(("EXT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
|
||||
LOG_0(("EXT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
|
||||
m_ext_signals[ PHI_488_EOI ] ,
|
||||
m_ext_signals[ PHI_488_DAV ] ,
|
||||
m_ext_signals[ PHI_488_NRFD ] ,
|
||||
@ -409,7 +411,7 @@ void phi_device::device_reset()
|
||||
|
||||
void phi_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
LOG(("tmr %d enabled %d\n" , id , timer.enabled()));
|
||||
LOG_0(("tmr %d enabled %d\n" , id , timer.enabled()));
|
||||
update_fsm();
|
||||
}
|
||||
|
||||
@ -521,7 +523,7 @@ uint8_t phi_device::get_dio(void)
|
||||
void phi_device::set_dio(uint8_t data)
|
||||
{
|
||||
if (data != m_dio) {
|
||||
LOG(("DIO=%02x\n" , data));
|
||||
LOG_0(("DIO=%02x\n" , data));
|
||||
m_dio = data;
|
||||
if (!m_loopback) {
|
||||
m_dio_write_func(~data);
|
||||
@ -542,7 +544,7 @@ void phi_device::set_signal(phi_488_signal_t signal , bool state)
|
||||
{
|
||||
if (state != m_signals[ signal ]) {
|
||||
m_signals[ signal ] = state;
|
||||
LOG(("INT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
|
||||
LOG_0(("INT EOI %d DAV %d NRFD %d NDAC %d IFC %d SRQ %d ATN %d REN %d\n" ,
|
||||
m_signals[ PHI_488_EOI ] ,
|
||||
m_signals[ PHI_488_DAV ] ,
|
||||
m_signals[ PHI_488_NRFD ] ,
|
||||
@ -565,9 +567,16 @@ void phi_device::pon_msg(void)
|
||||
m_t_spms = false;
|
||||
m_l_state = PHI_L_LIDS;
|
||||
m_sr_state = PHI_SR_NPRS;
|
||||
m_pp_state = PHI_PP_PPIS;
|
||||
m_pp_pacs = false;
|
||||
m_ppr_msg = my_address();
|
||||
uint8_t addr = my_address();
|
||||
if (addr <= 7) {
|
||||
// If address <= 7, PP is automatically enabled and configured for PPR = ~address
|
||||
m_ppr_msg = addr ^ 7;
|
||||
m_pp_state = PHI_PP_PPSS;
|
||||
} else {
|
||||
m_ppr_msg = 0;
|
||||
m_pp_state = PHI_PP_PPIS;
|
||||
}
|
||||
m_s_sense = true;
|
||||
m_c_state = PHI_C_CIDS;
|
||||
m_be_counter = 0;
|
||||
@ -610,10 +619,10 @@ void phi_device::update_fsm(void)
|
||||
// TODO: RL FSM
|
||||
// Loop until all changes settle
|
||||
while (changed) {
|
||||
LOG(("SH %d AH %d T %d SPMS %d L %d SR %d PP %d PACS %d PPR %u S %d C %d\n" ,
|
||||
LOG_0(("SH %d AH %d T %d SPMS %d L %d SR %d PP %d PACS %d PPR %u S %d C %d\n" ,
|
||||
m_sh_state , m_ah_state , m_t_state , m_t_spms , m_l_state , m_sr_state ,
|
||||
m_pp_state , m_pp_pacs , m_ppr_msg , m_s_sense , m_c_state));
|
||||
LOG(("O E/F=%d/%d I E/F=%d/%d\n" , m_fifo_out.empty() , m_fifo_out.full() , m_fifo_in.empty() , m_fifo_in.full()));
|
||||
LOG_0(("O E/F=%d/%d I E/F=%d/%d\n" , m_fifo_out.empty() , m_fifo_out.full() , m_fifo_in.empty() , m_fifo_in.full()));
|
||||
changed = false;
|
||||
|
||||
// SH FSM
|
||||
@ -641,7 +650,7 @@ void phi_device::update_fsm(void)
|
||||
if ((m_nba_origin = nba_msg(new_byte , new_eoi)) != NBA_NONE) {
|
||||
m_sh_state = PHI_SH_SDYS;
|
||||
m_sh_dly_timer->adjust(attotime::from_nsec(DELAY_T1));
|
||||
LOG(("SH DLY enabled %d\n" , m_sh_dly_timer->enabled()));
|
||||
LOG_0(("SH DLY enabled %d\n" , m_sh_dly_timer->enabled()));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -653,6 +662,7 @@ void phi_device::update_fsm(void)
|
||||
|
||||
case PHI_SH_STRS:
|
||||
if (!get_signal(PHI_488_NDAC)) {
|
||||
LOG(("TX %02x/%d\n" , m_dio , m_signals[ PHI_488_EOI ]));
|
||||
m_sh_state = PHI_SH_SGNS;
|
||||
clear_nba((nba_origin_t)m_nba_origin);
|
||||
}
|
||||
@ -669,15 +679,13 @@ void phi_device::update_fsm(void)
|
||||
|
||||
// SH outputs
|
||||
// EOI is controlled by SH & C FSMs
|
||||
bool eoi_signal;
|
||||
bool eoi_signal = false;
|
||||
uint8_t dio_byte = 0;
|
||||
set_signal(PHI_488_DAV , m_sh_state == PHI_SH_STRS);
|
||||
if (m_sh_state == PHI_SH_SDYS || m_sh_state == PHI_SH_STRS) {
|
||||
nba_msg(new_byte , new_eoi);
|
||||
set_dio(new_byte);
|
||||
dio_byte = new_byte;
|
||||
eoi_signal = new_eoi;
|
||||
} else {
|
||||
set_dio(0);
|
||||
eoi_signal = false;
|
||||
}
|
||||
|
||||
// AH FSM
|
||||
@ -883,8 +891,9 @@ void phi_device::update_fsm(void)
|
||||
changed = true;
|
||||
}
|
||||
// PP outputs
|
||||
if (m_pp_state == PHI_PP_PPAS && m_s_sense == !!BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT) && m_ppr_msg <= 7) {
|
||||
set_dio(1 << m_ppr_msg);
|
||||
if (m_pp_state == PHI_PP_PPAS && m_s_sense == !!BIT(m_reg_control , REG_CTRL_PP_RESPONSE_BIT)) {
|
||||
LOG(("PP %u\n" , m_ppr_msg));
|
||||
dio_byte |= (1U << m_ppr_msg);
|
||||
}
|
||||
|
||||
// C FSM
|
||||
@ -988,6 +997,7 @@ void phi_device::update_fsm(void)
|
||||
m_c_state == PHI_C_CAWS || m_c_state == PHI_C_CTRS);
|
||||
eoi_signal = eoi_signal || m_c_state == PHI_C_CPWS || m_c_state == PHI_C_CPPS;
|
||||
set_signal(PHI_488_EOI , eoi_signal);
|
||||
set_dio(dio_byte);
|
||||
}
|
||||
|
||||
// Update status register
|
||||
@ -1307,11 +1317,11 @@ bool phi_device::byte_received(uint8_t byte , bool eoi)
|
||||
if (m_l_state == PHI_L_LACS) {
|
||||
if (m_fifo_in.full() || BIT(m_reg_int_cond , REG_INT_DEV_CLEAR_BIT)) {
|
||||
// No room for received byte, stall handshake
|
||||
LOG(("..stalled\n"));
|
||||
LOG_0(("..stalled\n"));
|
||||
return false;
|
||||
} else {
|
||||
m_fifo_in.enqueue(word);
|
||||
LOG(("..OK\n"));
|
||||
LOG_0(("..OK\n"));
|
||||
if (m_t_state != PHI_T_TACS && m_t_state != PHI_T_ID3 &&
|
||||
m_t_state != PHI_T_ID5 && m_t_state != PHI_T_SPAS) {
|
||||
// If PHI didn't send this byte to itself, set data freeze
|
||||
@ -1320,7 +1330,7 @@ bool phi_device::byte_received(uint8_t byte , bool eoi)
|
||||
}
|
||||
}
|
||||
if (end_of_transfer) {
|
||||
LOG(("End of byte transfer enable\n"));
|
||||
LOG_0(("End of byte transfer enable\n"));
|
||||
m_fifo_out.dequeue();
|
||||
m_be_counter = 0;
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user