summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/hp9845_io/hp9885.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/hp9845_io/hp9885.cpp')
-rw-r--r--src/devices/bus/hp9845_io/hp9885.cpp974
1 files changed, 0 insertions, 974 deletions
diff --git a/src/devices/bus/hp9845_io/hp9885.cpp b/src/devices/bus/hp9845_io/hp9885.cpp
deleted file mode 100644
index e4a2fc9f33c..00000000000
--- a/src/devices/bus/hp9845_io/hp9885.cpp
+++ /dev/null
@@ -1,974 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders: F. Ulivi
-/*********************************************************************
-
- hp9885.cpp
-
- HP9885M 8" floppy drive
- =======================
-
- This driver implements HLE of HP9885 floppy drive.
- The HP9885M is a single-disk 8" floppy drive. It connects to
- main system through a HP98032 GPIO module. The controller in a
- HP9885M can drive 3 more external HP9885S drives. The "M" or "S"
- in the name stand for master and slave, respectively.
- The enclosure of HP9885M contains the floppy drive, the controller
- electronics and the power supply whereas the HP9885S only has the
- drive and the power supply. A master unit interfaces to slave units
- through a standard daisy-chained Shugart bus.
- The controller is based on a HP Nanoprocessor with a 2 kB FW ROM.
- Unfortunately no dumps are available of the ROM, AFAIK, so the HLE
- is needed.
- The HP9885 supports a single disk format having these characteristics:
- - Single side
- - HP MMFM modulation
- - 30 256-byte sectors per track
- - 77 tracks (only 67 are actually used)
- - 360 RPM
- - A total capacity of 514560 bytes per disk.
-
- Summary of the command words I identified
- =========================================
-
- *READ*
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----+-----+-----------------------------------+
- | 0 X|Unit#| Sector count |
- +-----+-----+-----------------------------------+
-
- Bit 14 selects tighter margin for data reading (not emulated here)
-
- *WRITE*
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----+-----+-----------------------------------+
- | 1 0|Unit#| Sector count |
- +-----+-----+-----------------------------------+
-
- *SEEK*
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----+-----+--------------------+--------------+
- | 1 1|Unit#| Track # [0..76] |Sector#[0..29]|
- +-----+-----+--------------------+--------------+
-
- *FORMAT TRACK* (not implemented yet)
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----+-----+--------------------+--------------+
- | 1 1|Unit#| Track # [0..76] | 0x1e |
- +-----+-----+--------------------+--------------+
-
- *STEP IN*
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----+-----+--------------------+--------------+
- | 1 1|Unit#| 0x7c | 0x1f |
- +-----+-----+--------------------+--------------+
-
- *ERASE TRACK* (not implemented yet)
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----+-----+--------------------+--------------+
- | 1 1|Unit#| 0x7d | 0x1f |
- +-----+-----+--------------------+--------------+
-
- *READ STATUS*
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----+-----+--------------------+--------------+
- | 1 1|Unit#| 0x7f | 0x1f |
- +-----+-----+--------------------+--------------+
-
- This is the structure of the status word:
-
- +-----------------------------------------------+
- |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|
- +-----------------------+--+--+--+--+--+--+-----+
- | Error code (0=OK) |--|XC|SC|NR|WP|DC|Unit#|
- +-----------------------+--+--+--+--+--+--+-----+
-
- DC: Disk changed
- WP: Write protection
- NR: Not ready
- SC: Seek completed
- XC: Transfer completed
-
- Usage on HP9825
- ===============
-
- -slot0 98032_gpio -slot0:98032_gpio:gpio hp9885 -flop <floppy image>
-
- Usage on HP9845
- ===============
-
- -slot0 98032_gpio -slot0:98032_gpio:gpio hp9885 -rom1 massd -flop <floppy image>
-
- Note on floppy images
- =====================
-
- Images can be in two formats: MFI & HPI.
- A pre-formatted image must be used as formatting is not supported.
- It's not possible to format images for two reasons: the format
- command is not implemented yet and no dump of the disk system tape
- cartridge (HP part no. 09885-90035) is available.
- The latter is needed during format operation to create the so-called
- bootstraps on disk, which in turn are needed by 9825 systems.
- A pre-formatted image (9825_empty.hpi) is available here:
- http://www.hpmuseum.net/software/9825_discs.zip
-
- TODO
- ====
-
- + Implement missing commands
- + PRESET
-
- Acknowledgments
- ===============
-
- Thanks to Dyke Shaffer for publishing a lot of HP internal docs
- and source files regarding the HP9885.
-
- Fun fact: data I/O between disk and 98032 module is not buffered
- as there is no RAM in the controller. DMA must be used to keep
- data flow at disk speed and avoid underruns. The nominal disk
- data rate is one word every 32 µs.
-
-*********************************************************************/
-
-#include "emu.h"
-#include "hp9885.h"
-#include "formats/hpi_dsk.h"
-
-// Debugging
-#include "logmacro.h"
-#define LOG_TIMER_MASK (LOG_GENERAL << 1)
-#define LOG_TIMER(...) LOGMASKED(LOG_TIMER_MASK, __VA_ARGS__)
-#define LOG_HS_MASK (LOG_TIMER_MASK << 1)
-#define LOG_HS(...) LOGMASKED(LOG_HS_MASK, __VA_ARGS__)
-#define LOG_HEAD_MASK (LOG_HS_MASK << 1)
-#define LOG_HEAD(...) LOGMASKED(LOG_HEAD_MASK, __VA_ARGS__)
-#define LOG_DISK_MASK (LOG_HEAD_MASK << 1)
-#define LOG_DISK(...) LOGMASKED(LOG_DISK_MASK, __VA_ARGS__)
-
-#undef VERBOSE
-//#define VERBOSE (LOG_GENERAL | LOG_HS_MASK | LOG_HEAD_MASK)
-#define VERBOSE 0
-
-// Bit manipulation
-namespace {
- template<typename T> constexpr T BIT_MASK(unsigned n)
- {
- return (T)1U << n;
- }
-
- template<typename T> void BIT_CLR(T& w , unsigned n)
- {
- w &= ~BIT_MASK<T>(n);
- }
-
- template<typename T> void BIT_SET(T& w , unsigned n)
- {
- w |= BIT_MASK<T>(n);
- }
-}
-
-// device type definition
-DEFINE_DEVICE_TYPE(HP9885, hp9885_device, "hp9885" , "HP9885 floppy drive")
-
-// Timers
-enum {
- FSM_TMR_ID,
- HEAD_TMR_ID,
- BIT_BYTE_TMR_ID
-};
-
-// Constants
-constexpr unsigned MAX_TRACK = 76; // Maximum valid track
-constexpr unsigned MAX_SECTOR = 29; // Maximum valid sector
-constexpr unsigned UNKNOWN_TRACK= 0xff; // Current track unknown
-constexpr unsigned STEP_MS = 8; // Step time (ms)
-constexpr unsigned SETTLING_MS = 8; // Settling time (ms)
-constexpr unsigned HEAD_TO_MS = 415; // Head unload timeout (ms)
-constexpr unsigned HD_SETTLE_MS = 50; // Head settling time (ms)
-constexpr uint16_t PASSWORD = 0xae87; // "Password" to enable commands
-constexpr unsigned HALF_CELL_US = 1; // Half bit cell duration (µs)
-constexpr unsigned STATUS_DELAY_US = 100; // Status delay (µs)
-constexpr unsigned MISSED_ID_REVS = 2; // Disk rotations to stop ID search
-
-// Bits in status word
-constexpr unsigned STS_DISK_CHANGED = 2; // Disk changed
-constexpr unsigned STS_WRITE_PROTECT= 3; // Write protection
-constexpr unsigned STS_NOT_RDY = 4; // Drive not ready
-constexpr unsigned STS_SEEK_COMPLETE= 5; // Seek completed
-constexpr unsigned STS_XFER_COMPLETE= 6; // Data transfer completed
-
-// Error codes
-enum : unsigned {
- ERR_NONE = 0,
- ERR_NOT_POWERED = 1,
- ERR_DOOR_OPEN = 2,
- ERR_NO_DISK = 3,
- ERR_WR_DISABLED = 4,
- ERR_ID_ERROR = 5,
- ERR_TRACK_ERROR = 6,
- ERR_CRC_ERROR = 7,
- ERR_HW_FAILURE = 8
-};
-
-hp9885_device::hp9885_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : hp98032_gpio_card_device(mconfig , HP9885 , tag , owner , clock)
- , m_drive_connector{*this , "floppy"}
-{
-}
-
-hp9885_device::~hp9885_device()
-{
-}
-
-uint16_t hp9885_device::get_jumpers() const
-{
- return hp98032_gpio_slot_device::JUMPER_2 |
- hp98032_gpio_slot_device::JUMPER_7 |
- hp98032_gpio_slot_device::JUMPER_8 |
- hp98032_gpio_slot_device::JUMPER_B |
- hp98032_gpio_slot_device::JUMPER_E |
- hp98032_gpio_slot_device::JUMPER_F;
-}
-
-uint16_t hp9885_device::input_r() const
-{
- uint16_t tmp = m_input;
- if (m_obf) {
- tmp |= m_output;
- LOG_HS("DATA OUT %04x\n" , tmp);
- }
- return tmp;
-}
-
-uint8_t hp9885_device::ext_status_r() const
-{
- return 0;
-}
-
-void hp9885_device::output_w(uint16_t data)
-{
- m_input = data;
-}
-
-void hp9885_device::ext_control_w(uint8_t data)
-{
- LOG_HS("EXT CTRL %u\n" , data);
- if (BIT(data , 0) &&
- !BIT(m_status , STS_XFER_COMPLETE) &&
- (m_op == OP_READ || m_op == OP_WRITE)) {
- // CTL0 terminates current data transfer
- LOG("xfer terminated\n");
- BIT_SET(m_status , STS_XFER_COMPLETE);
- // Prepare to output status
- set_output();
- }
-}
-
-WRITE_LINE_MEMBER(hp9885_device::pctl_w)
-{
- m_pctl = state;
- if (m_pctl) {
- if (!m_outputting) {
- set_ibf(true);
- }
- } else {
- LOG_HS("DATA IN %04x\n" , m_input);
- new_word();
- }
- update_busy();
-}
-
-WRITE_LINE_MEMBER(hp9885_device::io_w)
-{
- LOG_HS("I/O = %d\n" , state);
-}
-
-WRITE_LINE_MEMBER(hp9885_device::preset_w)
-{
- LOG("PRESET = %d\n" , state);
-}
-
-static const floppy_format_type hp9885_floppy_formats[] = {
- FLOPPY_MFI_FORMAT,
- FLOPPY_HPI_FORMAT,
- nullptr
-};
-
-void hp9885_device::device_add_mconfig(machine_config &config)
-{
- FLOPPY_CONNECTOR(config , "floppy" , "8ssdd" , FLOPPY_8_SSDD , true , hp9885_floppy_formats).set_fixed(true);
-}
-
-void hp9885_device::device_start()
-{
- save_item(NAME(m_input));
- save_item(NAME(m_output));
- save_item(NAME(m_status));
- save_item(NAME(m_fsm_state));
- save_item(NAME(m_head_state));
- save_item(NAME(m_op));
- save_item(NAME(m_pctl));
- save_item(NAME(m_ibf));
- save_item(NAME(m_obf));
- save_item(NAME(m_outputting));
- save_item(NAME(m_had_transition));
- save_item(NAME(m_dskchg));
- save_item(NAME(m_track));
- save_item(NAME(m_seek_track));
- save_item(NAME(m_seek_sector));
- save_item(NAME(m_sector_cnt));
- save_item(NAME(m_word_cnt));
- save_item(NAME(m_rev_cnt));
- save_item(NAME(m_am_detector));
- save_item(NAME(m_crc));
-
- m_fsm_timer = timer_alloc(FSM_TMR_ID);
- m_head_timer = timer_alloc(HEAD_TMR_ID);
- m_bit_byte_timer = timer_alloc(BIT_BYTE_TMR_ID);
-
- m_drive = m_drive_connector->get_device();
-
- m_drive->setup_ready_cb(floppy_image_device::ready_cb(&hp9885_device::floppy_ready_cb , this));
- m_drive->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&hp9885_device::floppy_index_cb , this));
-}
-
-void hp9885_device::device_reset()
-{
- eir_w(0);
- psts_w(1);
- m_dskchg = true;
- m_obf = false;
- recalibrate();
- m_seek_track = 0;
- m_seek_sector = 0;
- m_fsm_state = FSM_RECALIBRATING;
- set_state(FSM_IDLE);
-}
-
-void hp9885_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- LOG_TIMER("Tmr %.06f ID %d FSM %d HD %d\n" , machine().time().as_double() , id , m_fsm_state , m_head_state);
-
- switch (id) {
- case FSM_TMR_ID:
- do_FSM();
- break;
-
- case HEAD_TMR_ID:
- if (m_head_state == HEAD_SETTLING) {
- LOG_HEAD("%.06f Head loaded\n" , machine().time().as_double());
- m_head_state = HEAD_LOADED;
- // Trigger actions to be done on head loading
- do_FSM();
- m_head_timer->adjust(attotime::from_msec(HEAD_TO_MS - HD_SETTLE_MS));
- } else {
- LOG_HEAD("%.06f Head unloaded\n" , machine().time().as_double());
- m_head_state = HEAD_UNLOADED;
- }
- break;
-
- case BIT_BYTE_TMR_ID:
- {
- switch (m_fsm_state) {
- case FSM_WAIT_ID_AM:
- case FSM_WAIT_DATA_AM:
- {
- attotime edge;
- attotime tm;
- edge = m_drive->get_next_transition(m_pll.ctime);
- bool half_bit = m_pll.feed_read_data(tm , edge , attotime::never);
- m_am_detector <<= 1;
- m_am_detector |= half_bit;
- if (m_am_detector == 0x55552a54) {
- // ID AM
- // CDCDCDCDCDCDCDCD
- // 0 0 0 0 1 1 1 0
- // 0 1 1 1 0 0 0 0
- LOG_DISK("Got ID AM\n");
- preset_crc();
- m_word_cnt = 2;
- set_state(FSM_RD_ID);
- } else if (m_am_detector == 0x55552a44) {
- // DATA AM
- // CDCDCDCDCDCDCDCD
- // 0 0 0 0 1 0 1 0
- // 0 1 1 1 0 0 0 0
- LOG_DISK("Got Data AM\n");
- if (m_fsm_state == FSM_WAIT_DATA_AM) {
- m_rev_cnt = 0;
- if (BIT(m_status , STS_XFER_COMPLETE)) {
- output_status();
- return;
- } else {
- preset_crc();
- m_word_cnt = 129;
- if (m_op == OP_READ) {
- set_state(FSM_RD_DATA);
- } else {
- set_state(FSM_WR_DATA);
- m_pll.start_writing(m_pll.ctime);
- m_had_transition = false;
- wr_word(m_input);
- set_ibf(false);
- }
- }
- }
- }
- }
- break;
-
- case FSM_RD_ID:
- {
- // This is needed when state is switched to one of the AM waiting states
- m_am_detector = 0;
- auto word = rd_word();
- m_word_cnt--;
- LOG_DISK("W %04x C %u\n" , word , m_word_cnt);
- if (m_word_cnt && word != ((m_seek_sector << 8) | m_track)) {
- set_state(FSM_WAIT_ID_AM);
- } else if (m_word_cnt == 0) {
- if (m_crc) {
- LOG_DISK("Wrong CRC in ID\n");
- set_state(FSM_WAIT_ID_AM);
- } else {
- LOG_DISK("Sector found\n");
- set_state(FSM_WAIT_DATA_AM);
- }
- }
- }
- break;
-
- case FSM_RD_DATA:
- {
- auto word = rd_word();
- m_word_cnt--;
- LOG_DISK("W %04x C %u\n" , word , m_word_cnt);
- if (m_word_cnt >= 1) {
- if (!BIT(m_status , STS_XFER_COMPLETE)) {
- m_output = word;
- m_obf = true;
- update_busy();
- }
- } else if (m_word_cnt == 0) {
- if (m_crc) {
- LOG_DISK("Wrong CRC in data\n");
- }
- // Move to next sector
- adv_sector();
- if (BIT(m_status , STS_XFER_COMPLETE) || m_sector_cnt == 0) {
- BIT_SET(m_status , STS_XFER_COMPLETE);
- output_status();
- } else {
- set_state(FSM_POSITIONING);
- do_FSM();
- }
- return;
- }
- }
- break;
-
- case FSM_WR_DATA:
- {
- m_word_cnt--;
- if (m_word_cnt > 1) {
- if (BIT(m_status , STS_XFER_COMPLETE)) {
- wr_word(0);
- } else {
- wr_word(m_input);
- if (m_word_cnt > 2) {
- set_ibf(false);
- }
- }
- } else if (m_word_cnt == 1) {
- wr_word(m_crc);
- } else {
- m_pll.stop_writing(m_drive , m_pll.ctime);
- // Move to next sector
- adv_sector();
- if (BIT(m_status , STS_XFER_COMPLETE) || m_sector_cnt == 0) {
- BIT_SET(m_status , STS_XFER_COMPLETE);
- output_status();
- } else {
- set_ibf(false);
- set_state(FSM_POSITIONING);
- do_FSM();
- }
- return;
- }
- }
- break;
-
- default:
- LOG("Invalid FSM state %d\n" , m_fsm_state);
- set_state(FSM_IDLE);
- return;
- }
- timer.adjust(m_pll.ctime - machine().time());
- }
- break;
- }
-}
-
-void hp9885_device::floppy_ready_cb(floppy_image_device *floppy , int state)
-{
- LOG("ready %d\n" , state);
- if (state) {
- // drive not ready
- m_dskchg = true;
- }
-}
-
-void hp9885_device::floppy_index_cb(floppy_image_device *floppy , int state)
-{
- if (state && m_rev_cnt && --m_rev_cnt == 0) {
- // Sector not found
- LOG("Sector not found\n");
- stop_rdwr();
- set_error(ERR_ID_ERROR);
- output_status(true);
- }
-}
-
-void hp9885_device::set_state(int new_state)
-{
- if (m_fsm_state != new_state) {
- LOG("%.06f FSM %d->%d\n" , machine().time().as_double() , m_fsm_state , new_state);
- m_fsm_state = new_state;
- if (m_fsm_state == FSM_IDLE) {
- m_op = OP_NONE;
- m_outputting = false;
- set_ibf(false);
- m_fsm_timer->reset();
- stop_rdwr();
- m_rev_cnt = 0;
- }
- }
-}
-
-void hp9885_device::init_status(unsigned unit_no)
-{
- m_status = unit_no & 3;
- if (unit_no == 0) {
- if (m_drive->ready_r()) {
- BIT_SET(m_status , STS_NOT_RDY);
- }
- if (m_dskchg) {
- BIT_SET(m_status , STS_DISK_CHANGED);
- }
- if (m_drive->wpt_r()) {
- BIT_SET(m_status , STS_WRITE_PROTECT);
- }
- } else {
- // Units 1,2,3 are not present
- BIT_SET(m_status , STS_NOT_RDY);
- }
-}
-
-void hp9885_device::encode_error(bool writing)
-{
- if (m_status & 3) {
- set_error(ERR_NOT_POWERED);
- } else if (writing && BIT(m_status , STS_WRITE_PROTECT)) {
- set_error(ERR_WR_DISABLED);
- } else if (BIT(m_status , STS_NOT_RDY)) {
- set_error(ERR_NO_DISK);
- }
-}
-
-void hp9885_device::set_error(unsigned error_code)
-{
- m_status = (m_status & 0xff) | (error_code << 8);
- if (error_code != ERR_NONE) {
- LOG_HS("EIR 1\n");
- eir_w(1);
- psts_w(0);
- } else {
- LOG_HS("EIR 0\n");
- eir_w(0);
- psts_w(1);
- }
-}
-
-void hp9885_device::new_word()
-{
- unsigned unit_no = (m_input >> 12) & 3;
-
- switch (m_fsm_state) {
- case FSM_IDLE:
- if (m_input == PASSWORD) {
- LOG("Got PW\n");
- set_state(FSM_GOT_PW);
- } else {
- LOG("Wrong sequence\n");
- // TODO:
- // It probably does nothing IRL
- }
- set_ibf(false);
- break;
-
- case FSM_GOT_PW:
- // Decode new command
- switch (m_input & 0xc000) {
- case 0x0000:
- case 0x4000:
- // Read
- init_status(unit_no);
- if (!BIT(m_status , STS_NOT_RDY)) {
- m_sector_cnt = m_input & 0x0fff;
- LOG("Read %u sectors @%u:%u\n" , m_sector_cnt , m_seek_track , m_seek_sector);
- m_op = OP_READ;
- set_state(FSM_POSITIONING);
- if (load_head()) {
- m_fsm_timer->adjust(attotime::zero);
- }
- set_output();
- } else {
- encode_error(false);
- output_status();
- }
- break;
-
- case 0x8000:
- // Write
- init_status(unit_no);
- if (!BIT(m_status , STS_NOT_RDY) && !BIT(m_status , STS_WRITE_PROTECT)) {
- m_sector_cnt = m_input & 0x0fff;
- LOG("Write %u sectors @%u:%u\n" , m_sector_cnt , m_seek_track , m_seek_sector);
- m_op = OP_WRITE;
- set_state(FSM_POSITIONING);
- if (load_head()) {
- m_fsm_timer->adjust(attotime::zero);
- }
- set_ibf(false);
- } else {
- encode_error(true);
- output_status(true);
- }
- break;
-
- case 0xc000:
- {
- // Seek & other commands
- uint8_t track_no = (m_input >> 5) & 0x7f;
- uint8_t sect_no = m_input & 0x1f;
- if (sect_no == 0x1e) {
- // Format
- LOG("Format\n");
- // TODO:
- } else if (sect_no == 0x1f) {
- switch (track_no) {
- case 0x7c:
- // Step in
- init_status(unit_no);
- if (!BIT(m_status , STS_NOT_RDY)) {
- LOG("Step in\n");
- m_seek_track = m_track + 1;
- m_op = OP_STEP_IN;
- set_state(FSM_SEEKING);
- if (load_head()) {
- m_fsm_timer->adjust(attotime::zero);
- }
- } else {
- encode_error(false);
- output_status();
- }
- break;
-
- case 0x7d:
- // Write all track
- LOG("Write all track\n");
- // TODO:
- break;
-
- case 0x7f:
- // Read status
- init_status(unit_no);
- if (!BIT(m_status , STS_NOT_RDY) && BIT(m_status , STS_DISK_CHANGED)) {
- LOG("Get status DSKCHG\n");
- m_op = OP_GET_STATUS;
- set_state(FSM_POSITIONING);
- if (load_head()) {
- m_fsm_timer->adjust(attotime::zero);
- }
- } else {
- LOG("Get status !DSKCHG\n");
- encode_error(false);
- output_status();
- }
- break;
-
- default:
- LOG("Unknown command %02x\n" , track_no);
- }
- } else {
- // Plain seek
- LOG("Seek to %u:%u\n" , track_no , sect_no);
- m_seek_track = track_no;
- m_seek_sector = sect_no;
- set_state(FSM_IDLE);
- }
- }
- break;
- }
- break;
-
- case FSM_RD_STATUS1:
- set_error(ERR_NONE);
- set_state(FSM_RD_STATUS2);
- m_outputting = false;
- m_obf = false;
- break;
-
- case FSM_RD_STATUS2:
- set_state(FSM_IDLE);
- break;
-
- case FSM_RD_DATA:
- m_obf = false;
- break;
-
- default:
- if (m_op != OP_WRITE) {
- LOG("Got data in state %d!\n" , m_fsm_state);
- }
- }
-}
-
-void hp9885_device::do_FSM()
-{
- switch (m_fsm_state) {
- case FSM_RECALIBRATING:
- // Keep head loaded
- load_head();
- if (m_drive->trk00_r()) {
- one_step(true);
- } else {
- set_state(FSM_POSITIONING);
- m_fsm_timer->adjust(attotime::from_msec(SETTLING_MS));
- m_track = 0;
- }
- break;
-
- case FSM_SETTLING:
- if (m_op == OP_READ || m_op == OP_WRITE) {
- // Set seek complete
- BIT_SET(m_status , STS_SEEK_COMPLETE);
- if (m_sector_cnt--) {
- m_rev_cnt = MISSED_ID_REVS;
- set_state(FSM_WAIT_ID_AM);
- start_rd();
- } else {
- output_status();
- }
- } else if (m_op == OP_STEP_IN) {
- // Step IN
- // Set seek complete
- BIT_SET(m_status , STS_SEEK_COMPLETE);
- output_status();
- } else {
- // Get status
- output_status();
- }
- break;
-
- case FSM_POSITIONING:
- case FSM_SEEKING:
- // Keep head loaded
- load_head();
- // Need recalibration?
- if (m_track == UNKNOWN_TRACK) {
- set_state(FSM_RECALIBRATING);
- m_fsm_timer->adjust(attotime::zero);
- } else if (m_seek_track != m_track) {
- set_state(FSM_SEEKING);
- one_step(m_seek_track < m_track);
- } else {
- if (m_fsm_state == FSM_SEEKING) {
- m_fsm_timer->adjust(attotime::from_msec(SETTLING_MS));
- } else {
- m_fsm_timer->adjust(attotime::zero);
- }
- set_state(FSM_SETTLING);
- }
- break;
-
- case FSM_STATUS_DELAY:
- output_status();
- break;
-
- default:
- LOG("Invalid state=%d\n" , m_fsm_state);
- set_state(FSM_IDLE);
- }
- update_busy();
-}
-
-bool hp9885_device::load_head()
-{
- m_dskchg = false;
-
- switch (m_head_state) {
- case HEAD_UNLOADED:
- case HEAD_SETTLING:
- LOG_HEAD("%.06f Loading head..\n" , machine().time().as_double());
- m_head_state = HEAD_SETTLING;
- m_head_timer->adjust(attotime::from_msec(HD_SETTLE_MS));
- return false;
-
- case HEAD_LOADED:
- LOG_HEAD("%.06f Keep head loaded\n" , machine().time().as_double());
- m_head_timer->adjust(attotime::from_msec(HEAD_TO_MS));
- return true;
-
- default:
- LOG("Invalid head state %d\n" , m_head_state);
- m_head_state = HEAD_UNLOADED;
- return false;
- }
-}
-
-void hp9885_device::recalibrate()
-{
- m_track = UNKNOWN_TRACK;
-}
-
-void hp9885_device::one_step(bool outward)
-{
- if (outward) {
- if (m_track > 0) {
- m_track--;
- }
- } else {
- if (m_track < MAX_TRACK) {
- m_track++;
- }
- }
- LOG_HEAD("%.06f Step to trk %u\n" , machine().time().as_double() , m_track);
- m_drive->dir_w(outward);
- m_drive->stp_w(0);
- m_drive->stp_w(1);
- m_fsm_timer->adjust(attotime::from_msec(STEP_MS));
-}
-
-void hp9885_device::adv_sector()
-{
- if (++m_seek_sector > MAX_SECTOR) {
- m_seek_sector = 0;
- if (m_seek_track < MAX_TRACK) {
- m_seek_track++;
- }
- }
-}
-
-void hp9885_device::start_rd()
-{
- m_pll.set_clock(attotime::from_usec(HALF_CELL_US));
- m_pll.read_reset(machine().time());
- m_bit_byte_timer->adjust(attotime::zero);
- m_am_detector = 0;
-}
-
-void hp9885_device::stop_rdwr()
-{
- m_bit_byte_timer->reset();
-}
-
-uint16_t hp9885_device::rd_word()
-{
- uint16_t word = 0;
- for (unsigned i = 0; i < 16; ++i) {
- attotime edge;
- attotime tm;
- edge = m_drive->get_next_transition(m_pll.ctime);
- // Read & discard clock bit
- m_pll.feed_read_data(tm , edge , attotime::never);
- edge = m_drive->get_next_transition(m_pll.ctime);
- bool data_bit = m_pll.feed_read_data(tm , edge , attotime::never);
- word >>= 1;
- if (data_bit) {
- BIT_SET(word , 15);
- }
- update_crc(data_bit);
- }
- return word;
-}
-
-void hp9885_device::wr_word(uint16_t word)
-{
- for (unsigned i = 0; i < 16; ++i) {
- bool data_bit = BIT(word , i);
- bool clock_bit = !data_bit && !m_had_transition;
- m_had_transition = data_bit || clock_bit;
- attotime dummy;
-
- m_pll.write_next_bit(clock_bit , dummy , nullptr , attotime::never);
- m_pll.write_next_bit(data_bit , dummy , nullptr , attotime::never);
- update_crc(data_bit);
- }
- m_pll.commit(m_drive , m_pll.ctime);
-}
-
-void hp9885_device::preset_crc()
-{
- m_crc = ~0;
-}
-
-void hp9885_device::update_crc(bool bit)
-{
- bool crc_x15 = BIT(m_crc , 0);
- m_crc >>= 1;
- if (bit ^ crc_x15) {
- m_crc ^= 0x8408;
- }
-}
-
-void hp9885_device::set_ibf(bool state)
-{
- m_ibf = state;
- update_busy();
-}
-
-void hp9885_device::set_output()
-{
- m_outputting = true;
- m_obf = false;
- set_ibf(false);
-}
-
-void hp9885_device::output_status(bool delayed)
-{
- stop_rdwr();
- if (delayed) {
- set_output();
- set_state(FSM_STATUS_DELAY);
- m_fsm_timer->adjust(attotime::from_usec(STATUS_DELAY_US));
- } else {
- set_state(FSM_RD_STATUS1);
- m_outputting = true;
- m_obf = true;
- // Set status in output buffer
- m_output = m_status;
- set_ibf(false);
- }
-}
-
-void hp9885_device::update_busy()
-{
- bool busy = (!m_outputting && m_ibf) || (m_outputting && m_pctl && m_obf);
- LOG_HS("PCTL %d BUSY %d OUT %d IBF %d OBF %d\n" , m_pctl , busy , m_outputting , m_ibf , m_obf);
- pflg_w(!busy);
-}