pi1541/src/Drive.h
Alexander Martinelle 2d538e4975 Some code restructing and removed writeshiftregister use.
Moved the branching to Update.
writeShiftRegister renamed.
Fixed typo in main drive read.
Reorganised SetInput call try to trigger conditionals.
2019-09-04 22:06:21 +02:00

189 lines
5.3 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>
#if defined(EXPERIMENTALZERO)
inline int ceil(float num) {
int inum = (int)num;
if (num == (float)inum) {
return inum;
}
return inum + 1;
}
#endif
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();
#if defined(EXPERIMENTALZERO)
void DriveLoopWrite();
void DriveLoopRead();
void DriveLoopReadNoFluxNoCycles();
void DriveLoopReadNoFlux();
void DriveLoopReadNoCycles();
#endif
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:
#if defined(EXPERIMENTALZERO)
int32_t localSeed;
inline void ResetEncoderDecoder(unsigned int min, unsigned int /*max*/span)
{
UE7Counter = 16 - CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6)
UF4Counter = 0;
localSeed = ((localSeed * 1103515245) + 12345) & 0x7fffffff;
fluxReversalCyclesLeft = (span) * (localSeed >> 11) + min;
}
#else
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);
}
#endif
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.
// 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.
inline u32 AdvanceSectorPositionR(int& byteOffset)
{
++headBitOffset %= bitsInTrack;
byteOffset = headBitOffset >> 3;
return (~headBitOffset) & 7;
}
inline u32 AdvanceSectorPositionW(int& byteOffset)
{
byteOffset = headBitOffset >> 3;
u32 bit = (~headBitOffset) & 7;
++headBitOffset %= bitsInTrack;
return bit;
}
inline bool GetNextBit()
{
int byteOffset;
int bit = AdvanceSectorPositionR(byteOffset);
return diskImage->GetNextBit(headTrackPos, byteOffset, bit);
}
inline void SetNextBit(bool value)
{
int byteOffset;
int bit = AdvanceSectorPositionW(byteOffset);
diskImage->SetBit(headTrackPos, byteOffset, bit, 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;
#if defined(EXPERIMENTALZERO)
unsigned int cyclesLeftForBit;
unsigned int fluxReversalCyclesLeft;
unsigned int UE7Counter;
u32 writeShiftRegister;
#else
int UE7Counter;
u8 writeShiftRegister;
#endif
float cyclesForBit;
u32 readShiftRegister;
unsigned headTrackPos;
u32 headBitOffset;
float randomFluxReversalTime;
int UF4Counter;
int UE3Counter;
int CLOCK_SEL_AB;
bool SO;
unsigned char lastHeadDirection;
u32 bitsInTrack;
float cyclesPerBit;
bool motor;
bool LED;
};
#endif