mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-12-27 14:30:22 +00:00
tie disk spin-down to CPU cycles
This commit is contained in:
parent
f333780348
commit
c5e41a5ea7
@ -132,6 +132,7 @@ void AppleVM::cpuMaintenance(uint32_t cycles)
|
||||
}
|
||||
|
||||
keyboard->maintainKeyboard(cycles);
|
||||
disk6->maintenance(cycles);
|
||||
}
|
||||
|
||||
void AppleVM::Reset()
|
||||
|
140
apple/diskii.cpp
140
apple/diskii.cpp
@ -19,6 +19,9 @@
|
||||
|
||||
#define DISKIIMAGIC 0xAA
|
||||
|
||||
// how many CPU cycles do we wait to spin down the disk drive?
|
||||
#define SPINDOWNDELAY (1023)
|
||||
|
||||
DiskII::DiskII(AppleMMU *mmu)
|
||||
{
|
||||
this->mmu = mmu;
|
||||
@ -35,7 +38,7 @@ DiskII::DiskII(AppleMMU *mmu)
|
||||
lastDiskRead[0] = lastDiskRead[1] = 0;
|
||||
|
||||
disk[0] = disk[1] = NULL;
|
||||
indicatorIsOn[0] = indicatorIsOn[1] = 0;
|
||||
diskIsSpinningUntil[0] = diskIsSpinningUntil[1] = 0;
|
||||
selectedDisk = 0;
|
||||
}
|
||||
|
||||
@ -71,8 +74,24 @@ bool DiskII::Serialize(int8_t fd)
|
||||
return false;
|
||||
}
|
||||
|
||||
g_filemanager->writeByte(fd, indicatorIsOn[0]);
|
||||
g_filemanager->writeByte(fd, indicatorIsOn[1]);
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[0] & 0xFF000000) >> 24);
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[0] & 0x00FF0000) >> 16);
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[0] & 0x0000FF00) >> 8);
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[0] & 0x000000FF) );
|
||||
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[1] & 0xFF000000) >> 24);
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[1] & 0x00FF0000) >> 16);
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[1] & 0x0000FF00) >> 8);
|
||||
g_filemanager->writeByte(fd,
|
||||
(diskIsSpinningUntil[1] & 0x000000FF) );
|
||||
|
||||
|
||||
g_filemanager->writeByte(fd, selectedDisk);
|
||||
|
||||
@ -112,8 +131,15 @@ bool DiskII::Deserialize(int8_t fd)
|
||||
}
|
||||
}
|
||||
|
||||
indicatorIsOn[0] = g_filemanager->readByte(fd);
|
||||
indicatorIsOn[1] = g_filemanager->readByte(fd);
|
||||
diskIsSpinningUntil[0] = g_filemanager->readByte(fd);
|
||||
diskIsSpinningUntil[0] <<= 8;diskIsSpinningUntil[0] = g_filemanager->readByte(fd);
|
||||
diskIsSpinningUntil[0] <<= 8;diskIsSpinningUntil[0] = g_filemanager->readByte(fd);
|
||||
diskIsSpinningUntil[0] <<= 8;diskIsSpinningUntil[0] = g_filemanager->readByte(fd);
|
||||
|
||||
diskIsSpinningUntil[1] = g_filemanager->readByte(fd);
|
||||
diskIsSpinningUntil[1] <<= 8;diskIsSpinningUntil[1] = g_filemanager->readByte(fd);
|
||||
diskIsSpinningUntil[1] <<= 8;diskIsSpinningUntil[1] = g_filemanager->readByte(fd);
|
||||
diskIsSpinningUntil[1] <<= 8;diskIsSpinningUntil[1] = g_filemanager->readByte(fd);
|
||||
|
||||
selectedDisk = g_filemanager->readByte(fd);
|
||||
|
||||
@ -162,11 +188,13 @@ uint8_t DiskII::readSwitches(uint8_t s)
|
||||
break;
|
||||
|
||||
case 0x08: // drive off
|
||||
indicatorIsOn[selectedDisk] = 99;
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: delay a bit? Queue for later drawing? ***
|
||||
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".
|
||||
break;
|
||||
case 0x09: // drive on
|
||||
indicatorIsOn[selectedDisk] = 100;
|
||||
diskIsSpinningUntil[selectedDisk] = -1; // magic "forever"
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: delay a bit? Queue for later drawing? ***
|
||||
|
||||
// Start the given disk drive spinning
|
||||
@ -182,10 +210,6 @@ uint8_t DiskII::readSwitches(uint8_t s)
|
||||
|
||||
case 0x0C: // shift one read or write byte
|
||||
readWriteLatch = readOrWriteByte();
|
||||
/*
|
||||
if (readWriteLatch & 0x80)
|
||||
printf(" => Disk II reads 0x%.2X @ $%.4X\n", sequencer, g_cpu->pc);
|
||||
*/
|
||||
if (readWriteLatch & 0x80)
|
||||
sequencer = 0;
|
||||
break;
|
||||
@ -209,24 +233,6 @@ uint8_t DiskII::readSwitches(uint8_t s)
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: improve the spin-down here. We need a CPU cycle callback
|
||||
// for some period of time instead of this silly decrement counter ***
|
||||
if (!indicatorIsOn[selectedDisk]) {
|
||||
// printf("Unexpected read while disk isn't on?\n");
|
||||
indicatorIsOn[selectedDisk] = 100;
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: queue for later drawing?
|
||||
}
|
||||
if (indicatorIsOn[selectedDisk] > 0 && indicatorIsOn[selectedDisk] < 100) {
|
||||
// slowly spin it down...
|
||||
if (--indicatorIsOn[selectedDisk] == 0) {
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing?
|
||||
|
||||
// Stop the given disk drive spinning
|
||||
lastDiskRead[selectedDisk] = 0; // FIXME: magic value. We need a tristate for this. ***
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Any even address read returns the readWriteLatch (UTA2E Table 9.1,
|
||||
// p. 9-12, note 2)
|
||||
return (s & 1) ? FLOATING : readWriteLatch;
|
||||
@ -257,8 +263,17 @@ void DiskII::writeSwitches(uint8_t s, uint8_t v)
|
||||
break;
|
||||
|
||||
case 0x08: // drive off
|
||||
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".
|
||||
break;
|
||||
case 0x09: // drive on
|
||||
diskIsSpinningUntil[selectedDisk] = -1; // magic "forever"
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: delay a bit? Queue for later drawing? ***
|
||||
|
||||
// Start the given disk drive spinning
|
||||
lastDiskRead[selectedDisk] = g_cpu->cycles;
|
||||
break;
|
||||
|
||||
case 0x0A: // select drive 1
|
||||
@ -418,8 +433,11 @@ void DiskII::select(int8_t which)
|
||||
return;
|
||||
|
||||
if (which != selectedDisk) {
|
||||
#if 0
|
||||
*** fixme check if the drive is still "on"
|
||||
indicatorIsOn[selectedDisk] = 100; // spindown time (fixme)
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing?
|
||||
#endif
|
||||
|
||||
// set the selected disk drive
|
||||
selectedDisk = which;
|
||||
@ -445,40 +463,41 @@ uint8_t DiskII::readOrWriteByte()
|
||||
uint32_t curCycles = g_cpu->cycles;
|
||||
bool updateCycles = false;
|
||||
|
||||
if (lastDiskRead[selectedDisk] == 0) {
|
||||
// assume it's a first-read-after-spinup; return the first valid data
|
||||
sequencer = disk[selectedDisk]->nextDiskByte(curWozTrack[selectedDisk]);
|
||||
updateCycles = true;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Otherwise we figure out how many cycles we missed since the last
|
||||
// disk read, and pop the right number of bits off the woz track
|
||||
uint32_t missedCycles;
|
||||
missedCycles = curCycles - lastDiskRead[selectedDisk];
|
||||
|
||||
missedCycles >>= 2;
|
||||
if (missedCycles)
|
||||
updateCycles = true;
|
||||
while (missedCycles) {
|
||||
sequencer <<= 1;
|
||||
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
|
||||
missedCycles--;
|
||||
if (diskIsSpinningUntil[selectedDisk] >= curCycles) {
|
||||
|
||||
if (lastDiskRead[selectedDisk] == 0) {
|
||||
// assume it's a first-read-after-spinup; return the first valid data
|
||||
sequencer = disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
|
||||
updateCycles = true;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Otherwise we figure out how many cycles we missed since the last
|
||||
// disk read, and pop the right number of bits off the woz track
|
||||
uint32_t missedCycles;
|
||||
missedCycles = curCycles - lastDiskRead[selectedDisk];
|
||||
|
||||
missedCycles >>= 2;
|
||||
if (missedCycles)
|
||||
updateCycles = true;
|
||||
while (missedCycles) {
|
||||
sequencer <<= 1;
|
||||
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
|
||||
missedCycles--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
done:
|
||||
if (updateCycles) {
|
||||
// We only update the lastDiskRead counter if the number of passed
|
||||
// cycles indicates that we did some sort of work...
|
||||
lastDiskRead[selectedDisk] = curCycles;
|
||||
}
|
||||
|
||||
return sequencer;
|
||||
}
|
||||
|
||||
void DiskII::fillDiskBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
const char *DiskII::DiskName(int8_t num)
|
||||
{
|
||||
// ***
|
||||
@ -509,3 +528,18 @@ void DiskII::flushTrack(int8_t track, int8_t sel)
|
||||
|
||||
// ***
|
||||
}
|
||||
|
||||
void DiskII::maintenance(uint32_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] &&
|
||||
g_cpu->cycles > diskIsSpinningUntil[i]) {
|
||||
// Stop the given disk drive spinning
|
||||
lastDiskRead[i] = 0; // FIXME: magic value. We need a tristate for this. ***
|
||||
diskIsSpinningUntil[i] = 0;
|
||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + i, false); // FIXME: queue for later drawing?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ class DiskII : public Slot {
|
||||
const char *DiskName(int8_t num);
|
||||
void flushTrack(int8_t track, int8_t sel);
|
||||
|
||||
void fillDiskBuffer(); // called from main loop
|
||||
void maintenance(uint32_t cycles);
|
||||
|
||||
private:
|
||||
void setPhase(uint8_t phase);
|
||||
@ -63,7 +63,7 @@ class DiskII : public Slot {
|
||||
bool writeProt;
|
||||
AppleMMU *mmu;
|
||||
|
||||
volatile uint8_t indicatorIsOn[2];
|
||||
volatile uint32_t diskIsSpinningUntil[2];
|
||||
|
||||
volatile int8_t selectedDisk;
|
||||
};
|
||||
|
@ -422,9 +422,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
static uint32_t usleepcycles = 16384; // step-down for display drawing. Dynamically updated based on FPS calculations.
|
||||
|
||||
// fill disk buffer when needed
|
||||
((AppleVM*)g_vm)->disk6->fillDiskBuffer();
|
||||
|
||||
g_ui->blit();
|
||||
if (g_vm->vmdisplay->needsRedraw()) {
|
||||
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
||||
|
@ -293,9 +293,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
static uint32_t usleepcycles = 16384*4; // step-down for display drawing. Dynamically updated based on FPS calculations.
|
||||
|
||||
// fill disk buffer when needed
|
||||
((AppleVM*)g_vm)->disk6->fillDiskBuffer();
|
||||
|
||||
if (g_vm->vmdisplay->needsRedraw()) {
|
||||
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
||||
// make sure to clear the flag before drawing; there's no lock
|
||||
|
@ -244,8 +244,6 @@ void loop()
|
||||
biosInterrupt();
|
||||
}
|
||||
|
||||
((AppleVM*)g_vm)->disk6->fillDiskBuffer();
|
||||
|
||||
g_keyboard->maintainKeyboard();
|
||||
|
||||
//debugLCDState = !debugLCDState;
|
||||
|
Loading…
Reference in New Issue
Block a user