Ejemplo n.º 1
0
        /// <summary>
        /// Hardware reset of the card
        /// </summary>
        public void Reset()
        {
            // reset card
            m_reg_page            = 0;
            m_reg_param           = 0;
            m_fdc_reset_state     = true;
            m_current_drive_index = 0;

            // reset FDC1793
            m_fdc_status              = 0;
            m_fdc_status_mode         = 1;
            m_fdc_command             = 0;
            m_fdc_track               = 0;
            m_fdc_sector              = 0;
            m_fdc_data                = 0;
            m_fdc_last_step_direction = 0;

            m_head_loaded = false;

            m_data_count  = 0;
            m_data_length = 0;

            m_operation_state = OperationState.None;
        }
Ejemplo n.º 2
0
        /** Write1793() **********************************************/
        /** Write value V into WD1793 register A. Returns DRQ/IRQ   **/
        /** values.                                                 **/
        /*************************************************************/
        public void PortWrite(ushort in_address, byte in_value)
        {
            if ((in_address & 0x0f) != 8)
            {
                if ((in_address & 0x0f) == 3)
                {
                    //Debug.Write(in_value.ToString("X2") + " ");
                }
                else
                {
                    Debug.Write((in_address & 0x0f).ToString("X2") + ":" + in_value.ToString("X2") + " = ");
                }
            }

            switch (in_address & 0x0f)
            {
            // command address
            case PORT_COMMAND:
                m_fdc_command = in_value;

                // Reset interrupt request
                m_reg_hw_status &= ~(HardwareFlags.INT);

                // If it is FORCE-IRQ command...
                if ((in_value & 0xF0) == 0xD0)
                {
                    m_force_interrupt = (ForceInterruptFlags)(in_value & 0x0f);

                    Debug.WriteLine("Force interrupt: {0}", m_force_interrupt);

                    // Reset any executing command
                    m_data_length     = 0;
                    m_data_count      = 0;
                    m_operation_state = OperationState.None;

                    // Either reset BUSY flag or reset all flags if BUSY=0
                    if ((m_fdc_status & StatusFlags.BUSY) != 0)
                    {
                        m_fdc_status &= ~StatusFlags.BUSY;
                    }
                    else
                    {
                        m_fdc_status      = m_disk_drives[m_current_drive_index].Track == 0 ? StatusFlags.TRACK0 : 0;
                        m_fdc_status_mode = 1;
                    }

                    // Cause immediate interrupt if requested
                    if ((in_value & (byte)CommandFlags.IRQ) != 0)
                    {
                        m_reg_hw_status = HardwareFlags.INT;
                    }

                    // Done
                    return;
                }

                // If busy, drop out
                if ((m_fdc_status & StatusFlags.BUSY) != 0)
                {
                    break;
                }

                // Reset status register
                m_fdc_status    = 0x00;
                m_reg_hw_status = 0x00;

                // Depending on the command...
                switch (in_value & 0xF0)
                {
                // RESTORE (seek track 0)
                case 0x00:
                    Debug.WriteLine("Restore");

                    // command group I
                    m_fdc_status_mode = 1;

                    // set head load
                    m_head_loaded = ((in_value & (byte)CommandFlags.LOADHEAD) != 0);

                    m_fdc_last_step_direction = 0;

                    // if already at track zero
                    if (m_disk_drives[m_current_drive_index].Track == 0)
                    {
                        m_fdc_status     |= StatusFlags.TRACK0;
                        m_reg_hw_status  |= HardwareFlags.INT;
                        m_fdc_track       = 0;
                        m_operation_state = OperationState.None;
                    }
                    else
                    {
                        // not on the first track -> start operation
                        StartOperation((m_disk_drives[m_current_drive_index].Geometry.NumberOfTracks / 2) * SteppingDelays[in_value & (byte)CommandFlags.STEPRATE], StatusFlags.TRACK0 | (StatusFlags)(((in_value & (byte)CommandFlags.LOADHEAD) != 0) ? StatusFlags.HEADLOAD : 0), HardwareFlags.INT, 0);
                    }
                    break;

                // SEEK command
                case 0x10:
                    Debug.WriteLine("Seek: {0:x2}", m_fdc_data);

                    // command group I
                    m_fdc_status_mode = 1;

                    // set head load
                    m_head_loaded = ((in_value & (byte)CommandFlags.LOADHEAD) != 0);

                    if (m_fdc_data > m_fdc_track)
                    {
                        m_fdc_last_step_direction = 0;
                    }
                    else
                    {
                        m_fdc_last_step_direction = 0x20;
                    }

                    // Reset any executing command
                    m_data_count  = 0;
                    m_data_length = 0;

                    StartOperation(Math.Abs((int)m_fdc_data - (int)m_fdc_track) * SteppingDelays[in_value & (byte)CommandFlags.STEPRATE], (StatusFlags)(((in_value & (byte)CommandFlags.LOADHEAD) != 0) ? StatusFlags.HEADLOAD : 0), HardwareFlags.INT, m_fdc_data);
                    break;

                case 0x20: // STEP
                case 0x30: // STEP-AND-UPDATE
                case 0x40: // STEP-IN
                case 0x50: // STEP-IN-AND-UPDATE
                case 0x60: // STEP-OUT
                case 0x70: // STEP-OUT-AND-UPDATE
                {
                    Debug.Write(string.Format("Step: {0:x2}", (in_value & 0xF0)));

                    // command group I
                    m_fdc_status_mode = 1;

                    // set head load
                    m_head_loaded = ((in_value & (byte)CommandFlags.LOADHEAD) != 0);

                    // Either store or fetch step direction
                    if ((in_value & 0x40) != 0)
                    {
                        m_fdc_last_step_direction = (byte)(in_value & 0x20);
                    }
                    else
                    {
                        in_value = (byte)((in_value & ~0x20) | m_fdc_last_step_direction);
                    }

                    // Step the head, update track register if requested
                    byte target_track = m_disk_drives[m_current_drive_index].Track;
                    if ((in_value & 0x20) != 0)
                    {
                        if (m_disk_drives[m_current_drive_index].Track > 0)
                        {
                            target_track--;
                        }
                    }
                    else
                    {
                        if (target_track < m_disk_drives[m_current_drive_index].Geometry.NumberOfTracks - 1)
                        {
                            target_track++;
                        }
                    }
                    Debug.WriteLine(" Track: {0}", target_track);

                    //m_disk_drives[m_current_drive_index].Track = target_track;

                    // Update track register if requested
                    StatusFlags new_status = 0;
                    if ((in_value & (byte)CommandFlags.SETTRACK) != 0)
                    {
                        if (target_track >= m_disk_drives[m_current_drive_index].Geometry.NumberOfTracks)
                        {
                            new_status = StatusFlags.SEEKERR;
                        }

                        m_fdc_track = m_disk_drives[m_current_drive_index].Track;
                    }

                    StartOperation(SteppingDelays[in_value & (byte)CommandFlags.STEPRATE], new_status, HardwareFlags.INT, target_track);
                }
                break;

                // Track write
                case 0xF0:
                    Debug.Write("TrackWrite ");
                    // command group III
                    m_fdc_status_mode = 3;

                    m_operation_start_tick   = m_tvcomputer.GetCPUTicks();
                    m_operation_state        = OperationState.TrackWriteWaitForIndex;
                    m_prev_index_pulse_state = IsIndexPulse();

                    m_fdc_status    = StatusFlags.BUSY;
                    m_reg_hw_status = HardwareFlags.DRQ;

                    break;

                // Sector read
                case 0x80: // single sector read
                case 0x90: // multiple sector read
                    Debug.WriteLine("Sector read, T:{0:d}, S:{1:d}, H:{2:d}", m_fdc_track, m_fdc_sector, GetCurrentDriveSide());

                    // check drive
                    if (m_current_drive_index == InvalidDriveIndex || !m_disk_drives[m_current_drive_index].IsDiskPresent())
                    {
                        m_fdc_status = StatusFlags.NOTREADY;
                    }
                    else
                    {
                        // check sector and track address
                        if (m_fdc_track != m_disk_drives[m_current_drive_index].Track || m_fdc_sector <1 || m_fdc_sector> m_disk_drives[m_current_drive_index].Geometry.SectorPerTrack)
                        {
                            m_fdc_status      = StatusFlags.NOTFOUND;
                            m_reg_hw_status   = HardwareFlags.INT;
                            m_operation_state = OperationState.None;
                            m_fdc_status_mode = 2;
                            m_data_length     = 0;
                        }
                        else
                        {
                            m_disk_drives[m_current_drive_index].Track = m_fdc_track;

                            m_data_count           = 0;
                            m_data_length          = m_disk_drives[m_current_drive_index].Geometry.SectorLength * (((in_value & 0x10) != 0) ? m_disk_drives[m_current_drive_index].Geometry.SectorPerTrack - m_fdc_sector + 1 : 1);
                            m_operation_start_tick = m_tvcomputer.GetCPUTicks();
                            m_operation_state      = OperationState.SectorRead;
                            m_fdc_status           = StatusFlags.BUSY;
                            m_fdc_status_mode      = 2;
                            m_head_loaded          = true;

                            m_disk_drives[m_current_drive_index].SeekSector(m_fdc_sector, GetCurrentDriveSide());
                        }
                    }
                    break;

#if false
                case 0xA0:
                case 0xB0:                                 /* WRITE-SECTORS */
                    if (D->Verbose)
                    {
                        printf("WD1793: WRITE-SECTOR%s %c:%d:%d:%d (%02Xh)\n", V & 0x10 ? "S" : "", 'A' + D->Drive, D->Side, D->R[1], D->R[2], V);
                    }
                    /* Seek to the requested sector */
                    D->Ptr = SeekFDI(
                        D->Disk[D->Drive], D->Side, D->Track[D->Drive],
                        V & C_SIDECOMP ? !!(V & C_SIDE) : D->Side, D->R[1], D->R[2]
                        );
                    /* If seek successful, set up writing operation */
                    if (!D->Ptr)
                    {
                        if (D->Verbose)
                        {
                            printf("WD1793: WRITE ERROR\n");
                        }
                        D->R[0]       = (D->R[0] & ~F_ERRCODE) | F_NOTFOUND;
                        m_irq_pending = true;;
                    }
                    else
                    {
                        m_wr_length = D->Disk[D->Drive]->SecSize
                                      * (V & 0x10 ? (D->Disk[D->Drive]->Sectors - D->R[2] + 1) : 1);
                        D->R[0] |= F_BUSY | F_DRQ;
                        D->IRQ   = WD1793_DRQ;
                        D->Wait  = 255;
                    }
                    break;
#endif
                // Read address
                case 0xC0:
                    Debug.WriteLine("Read address", in_value);

                    m_crc_generator.Reset();
                    m_address_buffer[0] = GetCurrentDriveTrack();
                    m_address_buffer[1] = GetCurrentDriveSide();
                    m_address_buffer[2] = 1;
                    m_address_buffer[3] = GetCurrentSectorLength();
                    m_crc_generator.Add(m_address_buffer, 4);
                    m_address_buffer[4] = m_crc_generator.CRCLow;
                    m_address_buffer[5] = m_crc_generator.CRCHigh;
                    m_data_count        = 0;
                    m_data_length       = 6;
                    m_fdc_sector        = GetCurrentDriveTrack();

                    m_prev_index_pulse_state = IsIndexPulse();
                    m_operation_state        = OperationState.IDReadWaitForIndex;
                    m_fdc_status_mode        = 3;
                    m_head_loaded            = true;
                    break;

#if false
                    /* Read first sector address from the track */
                    if (!D->Disk[D->Drive])
                    {
                        D->Ptr = 0;
                    }
                    else
                    {
                        for (J = 0; J < 256; ++J)
                        {
                            D->Ptr = SeekFDI(
                                D->Disk[D->Drive],
                                D->Side, D->Track[D->Drive],
                                D->Side, D->Track[D->Drive], J
                                );
                            if (D->Ptr)
                            {
                                break;
                            }
                        }
                    }
                    /* If address found, initiate data transfer */
                    if (!D->Ptr)
                    {
                        if (D->Verbose)
                        {
                            printf("WD1793: READ-ADDRESS ERROR\n");
                        }
                        D->R[0]      |= F_NOTFOUND;
                        m_irq_pending = true;;
                    }
                    else
                    {
                        D->Ptr      = D->Disk[D->Drive]->Header;
                        m_rd_length = 6;
                        D->R[0]    |= F_BUSY | F_DRQ;
                        D->IRQ      = WD1793_DRQ;
                        D->Wait     = 255;
                    }
                    break;
#endif
#if false
                case 0xE0:                                 /* READ-TRACK */
                    if (D->Verbose)
                    {
                        printf("WD1793: READ-TRACK %d (%02Xh) UNSUPPORTED!\n", D->R[1], V);
                    }
                    break;

                case 0xF0:                                 /* WRITE-TRACK */
                    if (D->Verbose)
                    {
                        printf("WD1793: WRITE-TRACK %d (%02Xh) UNSUPPORTED!\n", D->R[1], V);
                    }
                    break;

                default:                                 /* UNKNOWN */
                    if (D->Verbose)
                    {
                        printf("WD1793: UNSUPPORTED OPERATION %02Xh!\n", V);
                    }
                    break;
#endif
                }
                break;

            // track register
            case PORT_TRACK:
                Debug.WriteLine("Track register set: {0:x2}", in_value);
                if ((m_fdc_status & StatusFlags.BUSY) == 0 && !m_fdc_reset_state)
                {
                    m_fdc_track = in_value;
                }
                break;

            // sector register
            case PORT_SECTOR:
                Debug.WriteLine("Sector register set: {0:x2}", in_value);
                if ((m_fdc_status & StatusFlags.BUSY) == 0 && !m_fdc_reset_state)
                {
                    m_fdc_sector = in_value;
                }
                break;

            case PORT_DATA:
                m_fdc_data = in_value;

                switch (m_operation_state)
                {
                case OperationState.TrackWriteGap:
                    m_track_write_id_buffer = (m_track_write_id_buffer << 8) | in_value;
                    break;
                }

                m_reg_hw_status &= ~HardwareFlags.DRQ;

                /*
                 *  if ((m_reg_hw_status & HardwareFlags.DRQ) == 0)
                 *  {
                 *    m_track_write_id_buffer = (m_track_write_id_buffer << 8) | in_value;
                 *  }
                 *  else
                 *  {
                 *    // data overrun occured
                 *    m_reg_hw_status = HardwareFlags.INT;
                 *    m_fdc_status |= StatusFlags.LOSTDATA;
                 *    m_operation_state = OperationState.None;
                 *  }
                 */
                break;

#if false
                // check track write mode
                if (m_read_write_mode != ReadWriteMode.TrackWrite)
                {
                    TrackWriteData(in_value);
                }
                else
                {
                    /* When writing data, store value to disk */
                    if (m_wr_length > 0)
                    {
                        Debug.WriteLine(string.Format("WD1793: EXTRA DATA WRITE (%02Xh)\n", in_value));
                    }
                    else
                    {
                        /* Write data */
                        *D->Ptr++ = V;
                        /* Decrement length */
                        if (--m_wr_length > 0)
                        {
                            /* Reset timeout watchdog */
                            D->Wait = 255;
                            /* Advance to the next sector as needed */
                            if (!(m_wr_length & (D->Disk[D->Drive]->SecSize - 1)))
                            {
                                ++D->R[2];
                            }
                        }
                        else
                        {
                            /* Write completed */
                            if (D->Verbose)
                            {
                                printf("WD1793: WRITE COMPLETED\n");
                            }
                            D->R[0]      &= ~(F_DRQ | F_BUSY);
                            m_irq_pending = true;;
                        }
                    }
                }

                // Save last written value
                m_fdc_data = in_value;
#endif


            // parameter register
            case PORT_PARAM:
                Debug.WriteLine("Param register set: {0}", (ParametersFlags)in_value);
                m_reg_param = (ParametersFlags)in_value;

                switch (m_reg_param & ParametersFlags.DriveSelectMask)
                {
                case ParametersFlags.DriveSelect0:
                    m_current_drive_index = 0;
                    break;

                case ParametersFlags.DriveSelect1:
                    m_current_drive_index = 1;
                    break;

                case ParametersFlags.DriveSelect2:
                    m_current_drive_index = 2;
                    break;

                case ParametersFlags.DriveSelect3:
                    m_current_drive_index = 3;
                    break;

                default:
                    m_current_drive_index = InvalidDriveIndex;
                    break;
                }
                break;

            // page register
            case PORT_PAGE:
                m_reg_page        = in_value;
                m_fdc_reset_state = false;

                break;
            }
        }