mirror of https://github.com/JorjBauer/aiie.git
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);
|
keyboard->maintainKeyboard(cycles);
|
||||||
|
disk6->maintenance(cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppleVM::Reset()
|
void AppleVM::Reset()
|
||||||
|
|
140
apple/diskii.cpp
140
apple/diskii.cpp
|
@ -19,6 +19,9 @@
|
||||||
|
|
||||||
#define DISKIIMAGIC 0xAA
|
#define DISKIIMAGIC 0xAA
|
||||||
|
|
||||||
|
// how many CPU cycles do we wait to spin down the disk drive?
|
||||||
|
#define SPINDOWNDELAY (1023)
|
||||||
|
|
||||||
DiskII::DiskII(AppleMMU *mmu)
|
DiskII::DiskII(AppleMMU *mmu)
|
||||||
{
|
{
|
||||||
this->mmu = mmu;
|
this->mmu = mmu;
|
||||||
|
@ -35,7 +38,7 @@ DiskII::DiskII(AppleMMU *mmu)
|
||||||
lastDiskRead[0] = lastDiskRead[1] = 0;
|
lastDiskRead[0] = lastDiskRead[1] = 0;
|
||||||
|
|
||||||
disk[0] = disk[1] = NULL;
|
disk[0] = disk[1] = NULL;
|
||||||
indicatorIsOn[0] = indicatorIsOn[1] = 0;
|
diskIsSpinningUntil[0] = diskIsSpinningUntil[1] = 0;
|
||||||
selectedDisk = 0;
|
selectedDisk = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,8 +74,24 @@ bool DiskII::Serialize(int8_t fd)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_filemanager->writeByte(fd, indicatorIsOn[0]);
|
g_filemanager->writeByte(fd,
|
||||||
g_filemanager->writeByte(fd, indicatorIsOn[1]);
|
(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);
|
g_filemanager->writeByte(fd, selectedDisk);
|
||||||
|
|
||||||
|
@ -112,8 +131,15 @@ bool DiskII::Deserialize(int8_t fd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
indicatorIsOn[0] = g_filemanager->readByte(fd);
|
diskIsSpinningUntil[0] = g_filemanager->readByte(fd);
|
||||||
indicatorIsOn[1] = 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);
|
selectedDisk = g_filemanager->readByte(fd);
|
||||||
|
|
||||||
|
@ -162,11 +188,13 @@ uint8_t DiskII::readSwitches(uint8_t s)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x08: // drive off
|
case 0x08: // drive off
|
||||||
indicatorIsOn[selectedDisk] = 99;
|
diskIsSpinningUntil[selectedDisk] = g_cpu->cycles + SPINDOWNDELAY; // 1 second lag
|
||||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: delay a bit? Queue for later drawing? ***
|
if (diskIsSpinningUntil[selectedDisk] == -1 ||
|
||||||
|
diskIsSpinningUntil[selectedDisk] == 0)
|
||||||
|
diskIsSpinningUntil[selectedDisk] = 2; // fudge magic numbers; 0 is "off" and -1 is "forever".
|
||||||
break;
|
break;
|
||||||
case 0x09: // drive on
|
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? ***
|
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, true); // FIXME: delay a bit? Queue for later drawing? ***
|
||||||
|
|
||||||
// Start the given disk drive spinning
|
// 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
|
case 0x0C: // shift one read or write byte
|
||||||
readWriteLatch = readOrWriteByte();
|
readWriteLatch = readOrWriteByte();
|
||||||
/*
|
|
||||||
if (readWriteLatch & 0x80)
|
|
||||||
printf(" => Disk II reads 0x%.2X @ $%.4X\n", sequencer, g_cpu->pc);
|
|
||||||
*/
|
|
||||||
if (readWriteLatch & 0x80)
|
if (readWriteLatch & 0x80)
|
||||||
sequencer = 0;
|
sequencer = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -209,24 +233,6 @@ uint8_t DiskII::readSwitches(uint8_t s)
|
||||||
break;
|
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,
|
// Any even address read returns the readWriteLatch (UTA2E Table 9.1,
|
||||||
// p. 9-12, note 2)
|
// p. 9-12, note 2)
|
||||||
return (s & 1) ? FLOATING : readWriteLatch;
|
return (s & 1) ? FLOATING : readWriteLatch;
|
||||||
|
@ -257,8 +263,17 @@ void DiskII::writeSwitches(uint8_t s, uint8_t v)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x08: // drive off
|
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;
|
break;
|
||||||
case 0x09: // drive on
|
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;
|
break;
|
||||||
|
|
||||||
case 0x0A: // select drive 1
|
case 0x0A: // select drive 1
|
||||||
|
@ -418,8 +433,11 @@ void DiskII::select(int8_t which)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (which != selectedDisk) {
|
if (which != selectedDisk) {
|
||||||
|
#if 0
|
||||||
|
*** fixme check if the drive is still "on"
|
||||||
indicatorIsOn[selectedDisk] = 100; // spindown time (fixme)
|
indicatorIsOn[selectedDisk] = 100; // spindown time (fixme)
|
||||||
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing?
|
g_ui->drawOnOffUIElement(UIeDisk1_activity + selectedDisk, false); // FIXME: queue for later drawing?
|
||||||
|
#endif
|
||||||
|
|
||||||
// set the selected disk drive
|
// set the selected disk drive
|
||||||
selectedDisk = which;
|
selectedDisk = which;
|
||||||
|
@ -445,40 +463,41 @@ uint8_t DiskII::readOrWriteByte()
|
||||||
uint32_t curCycles = g_cpu->cycles;
|
uint32_t curCycles = g_cpu->cycles;
|
||||||
bool updateCycles = false;
|
bool updateCycles = false;
|
||||||
|
|
||||||
if (lastDiskRead[selectedDisk] == 0) {
|
if (diskIsSpinningUntil[selectedDisk] >= curCycles) {
|
||||||
// assume it's a first-read-after-spinup; return the first valid data
|
|
||||||
sequencer = disk[selectedDisk]->nextDiskByte(curWozTrack[selectedDisk]);
|
if (lastDiskRead[selectedDisk] == 0) {
|
||||||
updateCycles = true;
|
// assume it's a first-read-after-spinup; return the first valid data
|
||||||
goto done;
|
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;
|
// Otherwise we figure out how many cycles we missed since the last
|
||||||
missedCycles = curCycles - lastDiskRead[selectedDisk];
|
// disk read, and pop the right number of bits off the woz track
|
||||||
|
uint32_t missedCycles;
|
||||||
missedCycles >>= 2;
|
missedCycles = curCycles - lastDiskRead[selectedDisk];
|
||||||
if (missedCycles)
|
|
||||||
updateCycles = true;
|
missedCycles >>= 2;
|
||||||
while (missedCycles) {
|
if (missedCycles)
|
||||||
sequencer <<= 1;
|
updateCycles = true;
|
||||||
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
|
while (missedCycles) {
|
||||||
missedCycles--;
|
sequencer <<= 1;
|
||||||
|
sequencer |= disk[selectedDisk]->nextDiskBit(curWozTrack[selectedDisk]);
|
||||||
|
missedCycles--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (updateCycles) {
|
if (updateCycles) {
|
||||||
// We only update the lastDiskRead counter if the number of passed
|
// We only update the lastDiskRead counter if the number of passed
|
||||||
// cycles indicates that we did some sort of work...
|
// cycles indicates that we did some sort of work...
|
||||||
lastDiskRead[selectedDisk] = curCycles;
|
lastDiskRead[selectedDisk] = curCycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sequencer;
|
return sequencer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskII::fillDiskBuffer()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *DiskII::DiskName(int8_t num)
|
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);
|
const char *DiskName(int8_t num);
|
||||||
void flushTrack(int8_t track, int8_t sel);
|
void flushTrack(int8_t track, int8_t sel);
|
||||||
|
|
||||||
void fillDiskBuffer(); // called from main loop
|
void maintenance(uint32_t cycles);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setPhase(uint8_t phase);
|
void setPhase(uint8_t phase);
|
||||||
|
@ -63,7 +63,7 @@ class DiskII : public Slot {
|
||||||
bool writeProt;
|
bool writeProt;
|
||||||
AppleMMU *mmu;
|
AppleMMU *mmu;
|
||||||
|
|
||||||
volatile uint8_t indicatorIsOn[2];
|
volatile uint32_t diskIsSpinningUntil[2];
|
||||||
|
|
||||||
volatile int8_t selectedDisk;
|
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.
|
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();
|
g_ui->blit();
|
||||||
if (g_vm->vmdisplay->needsRedraw()) {
|
if (g_vm->vmdisplay->needsRedraw()) {
|
||||||
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
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.
|
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()) {
|
if (g_vm->vmdisplay->needsRedraw()) {
|
||||||
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
AiieRect what = g_vm->vmdisplay->getDirtyRect();
|
||||||
// make sure to clear the flag before drawing; there's no lock
|
// make sure to clear the flag before drawing; there's no lock
|
||||||
|
|
|
@ -244,8 +244,6 @@ void loop()
|
||||||
biosInterrupt();
|
biosInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
((AppleVM*)g_vm)->disk6->fillDiskBuffer();
|
|
||||||
|
|
||||||
g_keyboard->maintainKeyboard();
|
g_keyboard->maintainKeyboard();
|
||||||
|
|
||||||
//debugLCDState = !debugLCDState;
|
//debugLCDState = !debugLCDState;
|
||||||
|
|
Loading…
Reference in New Issue