2d538e4975
Moved the branching to Update. writeShiftRegister renamed. Fixed typo in main drive read. Reorganised SetInput call try to trigger conditionals.
189 lines
5.3 KiB
C++
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
|