convert cpu cycle counter to int64_t

This commit is contained in:
Jorj Bauer 2020-08-02 09:06:15 -04:00
parent 0c2cf3f8ff
commit fc3a360e7e
18 changed files with 67 additions and 70 deletions

View File

@ -172,7 +172,7 @@ void AppleKeyboard::keyReleased(uint8_t k)
}
}
void AppleKeyboard::maintainKeyboard(uint32_t cycleCount)
void AppleKeyboard::maintainKeyboard(int64_t cycleCount)
{
if (anyKeyIsDown) {
if (startRepeatTimer) {

View File

@ -13,7 +13,7 @@ class AppleKeyboard : public VMKeyboard {
virtual void keyDepressed(uint8_t k);
virtual void keyReleased(uint8_t k);
virtual void maintainKeyboard(uint32_t cycleCount);
virtual void maintainKeyboard(int64_t cycleCount);
protected:
bool isVirtualKey(uint8_t kc);
@ -49,9 +49,9 @@ class AppleKeyboard : public VMKeyboard {
// repeatTimer is the cpu cycle count at which we would repeat again.
// (It also has the rollover problem once every 82 minutes.)
uint32_t startRepeatTimer;
int64_t startRepeatTimer;
uint8_t keyThatIsRepeating;
uint32_t repeatTimer;
int64_t repeatTimer;
};
#endif

View File

@ -127,7 +127,7 @@ void AppleVM::triggerPaddleInCycles(uint8_t paddleNum,uint16_t cycleCount)
paddleCycleTrigger[paddleNum] = cycleCount + g_cpu->cycles;
}
void AppleVM::cpuMaintenance(uint32_t cycles)
void AppleVM::cpuMaintenance(int64_t cycles)
{
for (uint8_t i=0; i<2; i++) {
if (paddleCycleTrigger[i] && cycles >= paddleCycleTrigger[i]) {

View File

@ -17,7 +17,7 @@ class AppleVM : public VM {
void Suspend(const char *fn);
void Resume(const char *fn);
void cpuMaintenance(uint32_t cycles);
void cpuMaintenance(int64_t cycles);
virtual void Reset();
void Monitor();

View File

@ -26,6 +26,9 @@
// 10 second delay before flushing
#define FLUSHDELAY (1023000 * 10)
#define SPINFOREVER -2
#define NOTSPINNING -1
DiskII::DiskII(AppleMMU *mmu)
{
this->mmu = mmu;
@ -39,11 +42,11 @@ DiskII::DiskII(AppleMMU *mmu)
readWriteLatch = 0x00;
sequencer = 0;
dataRegister = 0;
driveSpinupCycles[0] = driveSpinupCycles[1] = 0;
driveSpinupCycles[0] = driveSpinupCycles[1] = 0; // CPU cycle number when the disk drive spins up
deliveredDiskBits[0] = deliveredDiskBits[1] = 0;
disk[0] = disk[1] = NULL;
diskIsSpinningUntil[0] = diskIsSpinningUntil[1] = 0;
diskIsSpinningUntil[0] = diskIsSpinningUntil[1] = -1;
flushAt[0] = flushAt[1] = 0;
selectedDisk = 0;
}
@ -54,7 +57,7 @@ DiskII::~DiskII()
bool DiskII::Serialize(int8_t fd)
{
uint8_t buf[23] = { DISKIIMAGIC,
uint8_t buf[27] = { DISKIIMAGIC,
readWriteLatch,
sequencer,
dataRegister,
@ -87,13 +90,17 @@ bool DiskII::Serialize(int8_t fd)
buf[ptr++] = ((deliveredDiskBits[i] >> 16) & 0xFF);
buf[ptr++] = ((deliveredDiskBits[i] >> 8) & 0xFF);
buf[ptr++] = ((deliveredDiskBits[i] ) & 0xFF);
buf[ptr++] = (diskIsSpinningUntil[i] >> 56) & 0xFF;
buf[ptr++] = (diskIsSpinningUntil[i] >> 48) & 0xFF;
buf[ptr++] = (diskIsSpinningUntil[i] >> 40) & 0xFF;
buf[ptr++] = (diskIsSpinningUntil[i] >> 32) & 0xFF;
buf[ptr++] = (diskIsSpinningUntil[i] >> 24) & 0xFF;
buf[ptr++] = (diskIsSpinningUntil[i] >> 16) & 0xFF;
buf[ptr++] = (diskIsSpinningUntil[i] >> 8) & 0xFF;
buf[ptr++] = (diskIsSpinningUntil[i] ) & 0xFF;
// Safety check: keeping the hard-coded 23 and comparing against ptr.
// If we change the 23, also need to change the size of buf[] above
if (g_filemanager->write(fd, buf, 23) != ptr) {
// Safety check: keeping the hard-coded 27 and comparing against ptr.
// If we change the 27, also need to change the size of buf[] above
if (g_filemanager->write(fd, buf, 27) != ptr) {
return false;
}
@ -144,7 +151,7 @@ bool DiskII::Deserialize(int8_t fd)
for (int i=0; i<2; i++) {
uint8_t ptr = 0;
if (g_filemanager->read(fd, buf, 23) != 23)
if (g_filemanager->read(fd, buf, 27) != 27)
return false;
curHalfTrack[i] = buf[ptr++];
@ -173,6 +180,10 @@ bool DiskII::Deserialize(int8_t fd)
diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++];
diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++];
diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++];
diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++];
diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++];
diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++];
diskIsSpinningUntil[i] <<= 8; diskIsSpinningUntil[i] |= buf[ptr++];
if (disk[i])
delete disk[i];
@ -228,12 +239,8 @@ void DiskII::Reset()
void DiskII::driveOff()
{
if (diskIsSpinningUntil[selectedDisk] == -1) {
if (diskIsSpinningUntil[selectedDisk] == SPINFOREVER) {
diskIsSpinningUntil[selectedDisk] = g_cpu->cycles + SPINDOWNDELAY; // 1 second lag
if (diskIsSpinningUntil[selectedDisk] == -1 ||
diskIsSpinningUntil[selectedDisk] == 0)
diskIsSpinningUntil[selectedDisk] = 2; // fudge magic numbers; 0 is "off" and -1 is "forever".
// The drive-is-on-indicator is turned off later, when the disk
// actually spins down.
}
@ -247,13 +254,13 @@ void DiskII::driveOff()
void DiskII::driveOn()
{
if (diskIsSpinningUntil[selectedDisk] != -1) {
if (diskIsSpinningUntil[selectedDisk] != SPINFOREVER) {
// If the drive isn't already spinning, then start keeping track of how
// many bits we've delivered (so we can honor the disk bit-delivery time
// that might be in the Woz disk image).
driveSpinupCycles[selectedDisk] = g_cpu->cycles;
deliveredDiskBits[selectedDisk] = 0;
diskIsSpinningUntil[selectedDisk] = -1; // magic "forever"
diskIsSpinningUntil[selectedDisk] = SPINFOREVER;
}
// FIXME: does the sequencer get reset? Maybe if it's the selected disk? Or no?
// sequencer = 0;
@ -301,9 +308,6 @@ uint8_t DiskII::readSwitches(uint8_t s)
case 0x0C: // shift one read or write byte
readWriteLatch = readOrWriteByte();
if (readWriteLatch & 0x80) {
// static uint32_t lastC = 0;
// printf("%u: read data\n", g_cpu->cycles - lastC);
// lastC = g_cpu->cycles;
if (!(sequencer & 0x80)) {
// printf("SEQ RESET EARLY [1]\n");
}
@ -478,17 +482,10 @@ bool DiskII::isWriteProtected()
int64_t DiskII::calcExpectedBits()
{
// If the disk isn't spinning, then it can't be expected to deliver data
if (!diskIsSpinningUntil[selectedDisk])
if (diskIsSpinningUntil[selectedDisk]==NOTSPINNING)
return 0;
// Handle potential messy counter rollover
if (driveSpinupCycles[selectedDisk] > g_cpu->cycles) {
driveSpinupCycles[selectedDisk] = g_cpu->cycles-1;
if (driveSpinupCycles[selectedDisk] == 0) // avoid sitting on 0
driveSpinupCycles[selectedDisk]++;
}
uint32_t cyclesPassed = g_cpu->cycles - driveSpinupCycles[selectedDisk];
int64_t cyclesPassed = g_cpu->cycles - driveSpinupCycles[selectedDisk];
// This constant defines how fast the disk drive "spins".
// 4.0 is good for DOS 3.3 writes, and reads as 205ms in
// Copy 2+'s drive speed verifier.
@ -500,7 +497,7 @@ int64_t DiskII::calcExpectedBits()
// As-is, this won't read NIB files for some reason I haven't
// fully understood; but if you slow the disk down to /5.0,
// then they load?
uint64_t expectedDiskBits = (float)cyclesPassed / 3.90;
int64_t expectedDiskBits = (float)cyclesPassed / 3.90;
return expectedDiskBits - deliveredDiskBits[selectedDisk];
}
@ -585,19 +582,19 @@ void DiskII::select(int8_t which)
return;
if (which != selectedDisk) {
if (diskIsSpinningUntil[selectedDisk] == -1) {
if (diskIsSpinningUntil[selectedDisk] == SPINFOREVER) {
// FIXME: I'm not sure what the right behavior is here (read
// UTA2E and see if the state diagrams show the right
// behavior). This spins it down immediately based on something
// I read about the duoDisk not having both motors on
// simultaneously.
diskIsSpinningUntil[selectedDisk] = 0;
diskIsSpinningUntil[selectedDisk] = NOTSPINNING;
// FIXME: consume any disk bits that need to be consumed, and
// spin it down
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false);
// Spin up the other one though
diskIsSpinningUntil[which] = -1;
diskIsSpinningUntil[which] = SPINFOREVER;
g_ui->drawOnOffUIElement(UIeDisk1_activity + which, true);
}
@ -625,13 +622,13 @@ void DiskII::select(int8_t which)
uint8_t DiskII::readOrWriteByte()
{
if (!disk[selectedDisk]) {
//printf("reading from uninserted disk\n");
return 0xFF;
}
int32_t bitsToDeliver;
if (diskIsSpinningUntil[selectedDisk] < g_cpu->cycles) {
if (diskIsSpinningUntil[selectedDisk] != SPINFOREVER &&
diskIsSpinningUntil[selectedDisk] < g_cpu->cycles) {
// Uum, disk isn't spinning?
goto done;
}
@ -740,15 +737,15 @@ void DiskII::loadROM(uint8_t *toWhere)
#endif
}
void DiskII::maintenance(uint32_t cycle)
void DiskII::maintenance(int64_t cycle)
{
// Handle spin-down for the drive. Drives stay on for a second after
// the stop was noticed.
for (int i=0; i<2; i++) {
if (diskIsSpinningUntil[i] &&
if (diskIsSpinningUntil[i] != SPINFOREVER &&
g_cpu->cycles > diskIsSpinningUntil[i]) {
// Stop the given disk drive spinning
diskIsSpinningUntil[i] = 0;
diskIsSpinningUntil[i] = NOTSPINNING;
// FIXME: consume any disk bits that need to be consumed, and spin it down
g_ui->drawOnOffUIElement(UIeDisk1_activity + i, false);
}

View File

@ -35,7 +35,7 @@ class DiskII : public Slot {
const char *DiskName(int8_t num);
void maintenance(uint32_t cycles);
void maintenance(int64_t cycles);
uint8_t selectedDrive();
uint8_t headPosition(uint8_t drive);
@ -66,18 +66,18 @@ private:
volatile int8_t curPhase[2];
volatile uint8_t readWriteLatch;
volatile uint8_t sequencer, dataRegister; // diskII logic state sequencer vars
volatile uint64_t driveSpinupCycles[2];
volatile uint64_t deliveredDiskBits[2];
volatile int64_t driveSpinupCycles[2];
volatile int64_t deliveredDiskBits[2];
bool writeMode;
bool writeProt;
AppleMMU *mmu;
volatile uint32_t diskIsSpinningUntil[2];
volatile int64_t diskIsSpinningUntil[2];
volatile int8_t selectedDisk;
volatile uint32_t flushAt[2];
volatile int64_t flushAt[2];
};
#endif

2
cpu.h
View File

@ -183,7 +183,7 @@ class Cpu {
uint8_t y;
uint8_t flags;
uint32_t cycles;
int64_t cycles;
bool irqPending;

View File

@ -90,7 +90,7 @@ void write(void *arg, uint16_t address, uint8_t v)
static void *cpu_thread(void *dummyptr) {
struct timespec currentTime;
struct timespec nextCycleTime;
uint32_t nextSpeakerCycle = 0;
int64_t nextSpeakerCycle = 0;
#if 0
int policy;

View File

@ -18,11 +18,11 @@ void LinuxSpeaker::begin()
{
}
void LinuxSpeaker::toggle(uint32_t c)
void LinuxSpeaker::toggle(int64_t c)
{
}
void LinuxSpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
void LinuxSpeaker::maintainSpeaker(int64_t c, uint64_t microseconds)
{
}

View File

@ -34,7 +34,7 @@ static int do_gettime(struct timespec *tp) {
// adds the number of nanoseconds that 'cycles' takes to *start and
// returns it in *out
static void timespec_add_cycles(struct timespec *start,
int32_t cycles,
int64_t cycles,
struct timespec *out)
{
out->tv_sec = start->tv_sec;

View File

@ -9,8 +9,8 @@ class PhysicalSpeaker {
virtual void begin() = 0;
virtual void toggle(uint32_t c) = 0;
virtual void maintainSpeaker(uint32_t c, uint64_t microseconds) = 0;
virtual void toggle(int64_t c) = 0;
virtual void maintainSpeaker(int64_t c, uint64_t microseconds) = 0;
virtual void beginMixing() = 0;
virtual void mixOutput(uint8_t v) = 0;

View File

@ -258,7 +258,7 @@ int main(int argc, char *argv[])
g_speaker->begin();
uint32_t lastCycleCount = -1;
int64_t lastCycleCount = -1;
while (1) {
if (g_biosInterrupt) {
@ -293,7 +293,7 @@ int main(int argc, char *argv[])
}
static uint32_t usleepcycles = 16384*4; // step-down for display drawing. Dynamically updated based on FPS calculations.
static int64_t usleepcycles = 16384*4; // step-down for display drawing. Dynamically updated based on FPS calculations.
if (g_vm->vmdisplay->needsRedraw()) {
AiieRect what = g_vm->vmdisplay->getDirtyRect();
@ -409,7 +409,7 @@ void doDebugging()
g_display->debugMsg(buf);
break;
case D_SHOWCYCLES:
sprintf(buf, "%X", g_cpu->cycles);
sprintf(buf, "%llX", g_cpu->cycles);
g_display->debugMsg(buf);
break;
/*

View File

@ -29,7 +29,7 @@ static volatile uint32_t skippedSamples = 0;
#define SAMPLEBYTES sizeof(short)
volatile uint8_t audioRunning = 0;
volatile uint32_t lastFilledTime = 0;
volatile int64_t lastFilledTime = 0;
// Debugging by writing a wav file with the sound output...
@ -157,11 +157,11 @@ void SDLSpeaker::begin()
SDL_PauseAudio(0);
}
void SDLSpeaker::toggle(uint32_t c)
void SDLSpeaker::toggle(int64_t c)
{
pthread_mutex_lock(&togmutex);
uint32_t expectedCycleNumber = (float)c * (float)44100 / (float)g_speed;
int64_t expectedCycleNumber = (float)c * (float)44100 / (float)g_speed;
if (lastFilledTime == 0) {
lastFilledTime = expectedCycleNumber;
}
@ -217,7 +217,7 @@ void SDLSpeaker::toggle(uint32_t c)
pthread_mutex_unlock(&togmutex);
}
void SDLSpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
void SDLSpeaker::maintainSpeaker(int64_t c, uint64_t microseconds)
{
}

View File

@ -12,8 +12,8 @@ class SDLSpeaker : public PhysicalSpeaker {
virtual void begin();
virtual void toggle(uint32_t c);
virtual void maintainSpeaker(uint32_t c, uint64_t microseconds);
virtual void toggle(int64_t c);
virtual void maintainSpeaker(int64_t c, uint64_t microseconds);
virtual void beginMixing();
virtual void mixOutput(uint8_t v);

View File

@ -28,7 +28,7 @@ static int do_gettime(struct timespec *tp) {
// adds the number of nanoseconds that 'cycles' takes to *start and
// returns it in *out
static void timespec_add_cycles(struct timespec *start,
int32_t cycles,
int64_t cycles,
struct timespec *out)
{
out->tv_sec = start->tv_sec;

View File

@ -32,7 +32,7 @@ static volatile uint32_t skippedSamples; // Who knows where this will
// too long & restart all the
// constants)
static volatile uint8_t audioRunning = 0; // FIXME: needs constants abstracted
static volatile uint32_t lastFilledTime = 0;
static volatile int64_t lastFilledTime = 0;
// how full do we want the audio buffer before we start it playing?
#define AUDIO_WATERLEVEL 4096
@ -66,7 +66,7 @@ void TeensySpeaker::begin()
audioRunning = 0;
}
void TeensySpeaker::toggle(uint32_t c)
void TeensySpeaker::toggle(int64_t c)
{
// Figure out when the last time was that we put data in the audio buffer;
// then figure out how many audio buffer cycles we have to fill from that
@ -74,7 +74,7 @@ void TeensySpeaker::toggle(uint32_t c)
__disable_irq();
// We expect to have filled to this cycle number...
uint32_t expectedCycleNumber = (float)c * (float)AUDIO_SAMPLE_RATE_EXACT / (float)g_speed;
int64_t expectedCycleNumber = (float)c * (float)AUDIO_SAMPLE_RATE_EXACT / (float)g_speed;
// Dynamically initialize the lastFilledTime based on the start time of the
// audio channel.
if (lastFilledTime == 0)
@ -133,7 +133,7 @@ void TeensySpeaker::toggle(uint32_t c)
__enable_irq();
}
void TeensySpeaker::maintainSpeaker(uint32_t c, uint64_t microseconds)
void TeensySpeaker::maintainSpeaker(int64_t c, uint64_t microseconds)
{
begin(); // flush! Hack. FIXME.
}

View File

@ -18,9 +18,9 @@ class TeensySpeaker : public PhysicalSpeaker {
virtual void begin();
virtual void toggle(uint32_t c);
virtual void toggle(int64_t c);
virtual void maintainSpeaker();
virtual void maintainSpeaker(uint32_t c, uint64_t microseconds);
virtual void maintainSpeaker(int64_t c, uint64_t microseconds);
virtual void beginMixing();
virtual void mixOutput(uint8_t v);

View File

@ -9,7 +9,7 @@ class VMKeyboard {
virtual void keyDepressed(uint8_t k) = 0;
virtual void keyReleased(uint8_t k) = 0;
virtual void maintainKeyboard(uint32_t cycleCount) = 0;
virtual void maintainKeyboard(int64_t cycleCount) = 0;
};
#endif