hp9845: 9895 is 95% done, it works except for some minor issues

This commit is contained in:
fulivi 2017-01-25 14:29:14 +01:00
parent 96988a1482
commit eb1afb07d6
4 changed files with 716 additions and 5 deletions

View File

@ -16,15 +16,92 @@
// 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 HPMODE_SYNC_MAX 2400 // Maximum distance of transitions to synchronize in HP mode (nsec)
#define IBMMODE_SYNC_MIN 3400 // Minimum distance of transitions to synchronize in IBM mode (nsec)
#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"}}
{
}
@ -36,11 +113,217 @@ ioport_constructor hp9895_device::device_input_ports() const
#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_prev_transition));
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();
}
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;
break;
case BYTE_TMR_ID:
{
if (!m_accdata) {
// 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_bit = m_pll.feed_read_data(tm , edge , attotime::never);
if (half_bit) {
if (!m_prev_transition.is_never()) {
attotime delta{ edge - m_prev_transition };
LOG_0(("Time=%.7f, Prev @ %.7f, Edge @ %.7f, Delta=%.7f\n" , machine().time().as_double() , m_prev_transition.as_double() , edge.as_double() , delta.as_double()));
if ((m_hiden && delta > attotime::from_nsec(HPMODE_SYNC_MAX)) ||
(!m_hiden && delta < attotime::from_nsec(IBMMODE_SYNC_MIN))) {
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 {
// half_bit is 0 in the clock part of bit cell when in HP mode,
// whereas it's 1 in IBM mode
// 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) {
// 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;
}
}
}
}
m_prev_transition = edge;
}
} 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 +443,346 @@ WRITE16_MEMBER(hp9895_device::z80_m1_w)
}
}
WRITE8_MEMBER(hp9895_device::data_w)
{
attotime next_sdok{get_time_next_sdok()};
LOG_0(("W DATA=%02x next SDOK @ %.6f\n" , data , next_sdok.as_double()));
// CPU stalls until next SDOK
m_cpu->spin_until_time(next_sdok - m_cpu->local_time());
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)
{
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_prev_transition = attotime::never;
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()) {
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;
attotime next_sdok{get_time_next_sdok()};
LOG_0(("R DATA=%02x next SDOK @ %.6f\n" , m_data_sr , next_sdok.as_double()));
// CPU stalls until next SDOK
m_cpu->spin_until_time(next_sdok - m_cpu->local_time());
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();
// TODO:
return res;
}
READ8_MEMBER(hp9895_device::switches2_r)
{
return get_switches2();
}
void hp9895_device::floppy_ready_cb(floppy_image_device *floppy , int state)
{
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;
}
}
attotime hp9895_device::get_time_next_sdok(void) const
{
if (m_byte_timer->enabled()) {
return m_byte_timer->expire();
} else if (m_mgnena && m_timeout_timer->enabled()) {
return m_timeout_timer->expire();
} else {
return attotime::never;
}
}
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 +798,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 +829,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

View File

@ -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
@ -29,6 +31,7 @@ public:
//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,68 @@ 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 ];
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
attotime m_prev_transition;
bool m_hiden;
bool m_mgnena;
// 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;
attotime get_time_next_sdok(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

View File

@ -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

View File

@ -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);