pi1541/Drive.h
2018-05-20 14:53:34 +10:00

128 lines
3.9 KiB
C++

// Pi1541 - A Commodore 1541 disk drive emulator
// Copyright(C) 2018 Stephen White
//
// This file is part of Pi1541.
//
// Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
#ifndef DRIVE_H
#define DRIVE_H
#include "m6522.h"
#include "DiskImage.h"
#include <stdlib.h>
class Drive
{
public:
Drive();
void SetVIA(m6522* pVIA)
{
m_pVIA = pVIA;
pVIA->GetPortB()->SetPortOut(this, OnPortOut);
}
static void OnPortOut(void*, unsigned char status);
bool Update();
void Insert(DiskImage* diskImage);
inline const DiskImage* GetDiskImage() const { return diskImage; }
void Eject();
void Reset();
inline unsigned Track() const { return headTrackPos; }
inline unsigned SectorPos() const { return headBitOffset >> 3; }
inline unsigned GetHeadBitOffset() const { return headBitOffset; }
inline bool IsMotorOn() const { return motor; }
inline bool IsLEDOn() const { return LED; }
inline unsigned char GetLastHeadDirection() const { return lastHeadDirection; } // For simulated head movement sounds
private:
inline float GenerateRandomFluxReversalTime(float min, float max) { return ((max - min) * ((float)rand() / RAND_MAX)) + min; } // Inputs in micro seconds
inline void ResetEncoderDecoder(float min, float max)
{
UE7Counter = CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6)
UF4Counter = 0;
randomFluxReversalTime = GenerateRandomFluxReversalTime(min, max);
}
inline void UpdateHeadSectorPosition()
{
// Disk spins at 300rpm = 5rps so to calculate how many 16Mhz cycles one rotation takes;-
// 16000000 / 5 = 3200000;
static const float CYCLES_16Mhz_PER_ROTATION = 3200000.0f;
bitsInTrack = diskImage->BitsInTrack(headTrackPos);
headBitOffset %= bitsInTrack;
cyclesPerBit = CYCLES_16Mhz_PER_ROTATION / (float)bitsInTrack;
}
inline void MoveHead(unsigned char headDirection)
{
if (lastHeadDirection != headDirection)
{
if (((lastHeadDirection - 1) & 3) == headDirection)
{
if (headTrackPos > 0) headTrackPos--;
// else head bang
}
else if (((lastHeadDirection + 1) & 3) == headDirection)
{
if (headTrackPos < HALF_TRACK_COUNT - 1) headTrackPos++;
}
lastHeadDirection = headDirection;
UpdateHeadSectorPosition();
}
}
void DumpTrack(unsigned track); // Used for debugging disk images.
u32 AdvanceSectorPositionR(int& byte_offset); // No reason why I seperate these into individual read and write versions. I was just trying to get the bit stream to line up when rewriting over existing data.
u32 AdvanceSectorPositionW(int& byte_offset);
bool GetNextBit();
void SetNextBit(bool value);
DiskImage* diskImage;
// When swapping disks some code waits for the write protect signal to go high which will happen if a human ejects a disk.
// Emulate this by asserting the write protect signal for a few cycles before inserting the new disk image.
u32 newDiskImageQueuedCylesRemaining;
// CA1 (input)
// - !BYTE SYNC
// CA2 (output)
// - BYTE SYNC enable
// CB1 (NC)
// - check pulled H/L
// CB2 (output)
// - R/!W
m6522* m_pVIA;
float cyclesForBit;
u32 readShiftRegister;
unsigned headTrackPos;
u32 headBitOffset;
float randomFluxReversalTime;
int UE7Counter;
int UF4Counter;
int UE3Counter;
int CLOCK_SEL_AB;
bool SO;
unsigned char lastHeadDirection;
u32 bitsInTrack;
float cyclesPerBit;
bool motor;
bool LED;
u8 writeShiftRegister;
};
#endif