int wd2793GetDataRequest(WD2793* wd) { sync(wd); if (((wd->regCommand & 0xF0) == 0xF0) && ((wd->regStatus & ST_BUSY) || wd->dataReady)) { UInt32 pulses = (boardSystemTime() - wd->dataRequsetTime) / (boardFrequency() / 5); if (wd->dataReady) { wd->dataRequest = 1; } if (pulses > 0) { wd->dataReady = 1; } if (pulses > 1) { wd->dataAvailable = 0; wd->sectorOffset = 0; wd->dataRequest = 0; wd->intRequest = 1; wd->regStatus &= ~ST_BUSY; } } if ((wd->regCommand & 0xe0) == 0x80 && (wd->regStatus & ST_BUSY)) { UInt32 pulses = (boardSystemTime() - wd->dataRequsetTime) / (boardFrequency() / 25); if (wd->dataReady) { wd->dataRequest = 1; } if (pulses > 0) { wd->dataReady = 1; } } return wd->dataRequest; }
static UInt8 getTimerCounter(RomMapperTurboRPcm* rm) { UInt64 elapsed; UInt32 systemTime = boardSystemTime(); elapsed = 15750 * (UInt64)(systemTime - rm->refTime) + rm->refFrag; rm->refTime = systemTime; rm->refFrag = (UInt32)(elapsed % boardFrequency()); rm->time += (UInt8)(elapsed / boardFrequency()); return rm->time & 0x03; }
static UInt16 counterGetElapsedTime(Counter* counter) { UInt64 elapsed; UInt32 elapsedTime; UInt32 systemTime = boardSystemTime(); elapsed = counter->frequency * (UInt64)(systemTime - counter->refTime) + counter->refFrag; counter->refTime = systemTime; counter->refFrag = (UInt32)(elapsed % boardFrequency()); elapsedTime = (UInt32)(elapsed / boardFrequency()); return (UInt16)elapsedTime; }
//------------------------------------------------------ // Board supports one external periodic timer (can be // used to sync external components with the emulation) // The callback needs to be added before the emulation // starts in order to be called. //------------------------------------------------------ void boardSetPeriodicCallback(BoardTimerCb cb, void* ref, UInt32 freq) { periodicCb = cb; periodicRef = ref; if (periodicCb != NULL && freq > 0) { periodicInterval = boardFrequency() / freq; } }
static void ym2148WriteCommand(YM2148* midi, UInt8 value) { midi->command = value; if (value & 0x02) { } if (value & CMD_RST) { ym2148Reset(midi); } midi->charTime = (UInt32)((UInt64)144 * boardFrequency() / 500000); }
UInt8 coinDeviceRead(CoinDevice* coinDev) { if(coinDev->time == 0 && inputEventGetState(EC_C)) { coinDev->time = boardSystemTime(); } if (coinDev->time != 0) { if ((boardSystemTime() - coinDev->time) < boardFrequency() * 2 / 10) { return 0; } coinDev->time = 0; } return 1; }
static void rtcUpdateRegs(RTC* rtc) { int carryDays; int carryYears; UInt64 elapsed; UInt32 elapsedTime; UInt32 systemTime = boardSystemTime(); elapsed = 16384 * (UInt64)(systemTime - rtc->refTime) + rtc->refFrag; rtc->refTime = systemTime; rtc->refFrag = (UInt32)(elapsed % boardFrequency()); elapsedTime = (UInt32)(elapsed / boardFrequency()); rtc->fraction += (rtc->modeReg & MODE_TIMERENABLE) ? elapsedTime : 0; rtc->seconds += (rtc->testReg & TEST_SECONDS) ? elapsedTime : rtc->fraction / 16384; rtc->fraction %= 16384; rtc->minutes += (rtc->testReg & TEST_MINUTES) ? elapsedTime : rtc->seconds / 60; rtc->seconds %= 60; rtc->hours += rtc-> minutes / 60; rtc->minutes %= 60; carryDays = (rtc->testReg & TEST_DAYS) ? elapsedTime : rtc->hours / 24; rtc->days += carryDays; rtc->hours %= 24; rtc->dayWeek = (rtc->dayWeek + carryDays) % 7; while (rtc->days >= daysInMonth[rtc->leapYear][rtc->months]) { rtc->days -= daysInMonth[rtc->leapYear][rtc->months]; rtc->months++; } carryYears = (rtc->testReg & TEST_YEARS) ? elapsedTime : rtc->months / 12; rtc->years = (rtc->years + carryYears) % 100; rtc->months %= 12; rtc->leapYear = (rtc->leapYear + carryYears) % 4; rtcSetRegisters(rtc); }
void philipsMidiReset(PhilipsMidi* midi) { midi->status = STAT_TXEMPTY; midi->txPending = 0; midi->rxPending = 0; midi->command = 0; midi->timeRecv = 0; midi->timeTrans = 0; midi->charTime = 10 * boardFrequency() / 31250; boardTimerRemove(midi->timerRecv); boardTimerRemove(midi->timerTrans); midi->timeRecv = boardSystemTime() + midi->charTime; boardTimerAdd(midi->timerRecv, midi->timeRecv); }
UInt8 wd2793PeekStatusReg(WD2793* wd) { UInt8 regStatus; sync(wd); regStatus = wd->regStatus; if (((wd->regCommand & 0x80) == 0) || ((wd->regCommand & 0xf0) == 0xd0)) { regStatus &= ~(ST_INDEX | ST_TRACK00 | ST_HEAD_LOADED | ST_WRITE_PROTECTED); if (diskEnabled(wd->drive)) { if (diskPresent(wd->drive)) { if ((UInt64)160 * boardSystemTime() / boardFrequency() & 0x1e) { regStatus |= ST_INDEX; } } if (wd->diskTrack == 0) { regStatus |= ST_TRACK00; } if (wd->headLoaded) { regStatus |= ST_HEAD_LOADED; } } else { regStatus |= ST_WRITE_PROTECTED; } } else { if (wd2793PeekDataRequest(wd)) { regStatus |= ST_DATA_REQUEST; } else { regStatus &= ~ST_DATA_REQUEST; } } if (diskPresent(wd->drive)) { regStatus &= ~ST_NOT_READY; } else { regStatus |= ST_NOT_READY; } return regStatus; }
static void counterSetTimeout(Counter* counter) { int nextTimeout = 0; int mode = counter->mode; // If counter is disabled, just return if (mode != 1 && mode != 5 && counter->gate == 0) { return; } if (counter->outPhase == 1) { nextTimeout = counter->countingElement - counter->endOutPhase1; } else if (counter->outPhase == 2) { nextTimeout = counter->countingElement - counter->endOutPhase2; } if (nextTimeout != 0) { counter->time = boardSystemTime() + (UInt64)boardFrequency() * nextTimeout / counter->frequency; boardTimerAdd(counter->timer, counter->time); } }
int wd2793PeekDataRequest(WD2793* wd) { int dataRequest = wd->dataRequest; if (((wd->regCommand & 0xF0) == 0xF0) && ((wd->regStatus & ST_BUSY) || wd->dataReady)) { UInt32 pulses = (boardSystemTime() - wd->dataRequsetTime) / (boardFrequency() / 5); if (wd->dataReady) { dataRequest = 1; } if (pulses > 1) { dataRequest = 0; } } if ((wd->regCommand & 0xe0) == 0x80 && (wd->regStatus & ST_BUSY)) { // UInt32 pulses = (boardSystemTime() - wd->dataRequsetTime) / (boardFrequency() / 25); if (wd->dataReady) { dataRequest = 1; } } return dataRequest; }
void philipsMidiWriteCommand(PhilipsMidi* midi, UInt8 value) { int baudrate = 1; int dataBits = 8; int parityEnable = 0; int stopBits = 1; UInt64 charLength; midi->command = value; switch (value & 0x03) { case 0: baudrate = 1; break; case 1: baudrate = 16; break; case 2: baudrate = 64; break; case 3: philipsMidiReset(midi); break; } switch (value & 0x1c) { case 0: dataBits = 7; parityEnable = 1; stopBits = 2; break; case 1: dataBits = 7; parityEnable = 1; stopBits = 2; break; case 2: dataBits = 7; parityEnable = 1; stopBits = 1; break; case 3: dataBits = 7; parityEnable = 1; stopBits = 1; break; case 4: dataBits = 8; parityEnable = 0; stopBits = 2; break; case 5: dataBits = 8; parityEnable = 0; stopBits = 1; break; case 6: dataBits = 8; parityEnable = 0; stopBits = 1; break; case 7: dataBits = 8; parityEnable = 1; stopBits = 1; break; } charLength = (dataBits + parityEnable + stopBits) * baudrate; midi->charTime = (UInt32)(charLength * boardFrequency() / 500000); midi->timeRecv = boardSystemTime() + midi->charTime; boardTimerAdd(midi->timerRecv, midi->timeRecv); }
void mixerSync(Mixer* mixer) { UInt32 systemTime = boardSystemTime(); Int16* buffer = mixer->buffer; Int32* chBuff[MAX_CHANNELS]; UInt32 count; UInt64 elapsed; int i; elapsed = mixer->rate * (UInt64)(systemTime - mixer->refTime) + mixer->refFrag; mixer->refTime = systemTime; mixer->refFrag = (UInt32)(elapsed % (mixerCPUFrequency * (boardFrequency() / 3579545))); count = (UInt32)(elapsed / (mixerCPUFrequency * (boardFrequency() / 3579545))); if (count == 0 || count > AUDIO_MONO_BUFFER_SIZE) { return; } if (!mixer->enable) { while (count--) { if (mixer->stereo) { buffer[mixer->index++] = 0; buffer[mixer->index++] = 0; } else { buffer[mixer->index++] = 0; } if (mixer->index == mixer->fragmentSize) { if (mixer->writeCallback != NULL) { mixer->writeCallback(mixer->writeRef, buffer, mixer->fragmentSize); } if (mixer->logging) { fwrite(buffer, 2 * mixer->fragmentSize, 1, mixer->file); } mixer->index = 0; } } return; } for (i = 0; i < mixer->channelCount; i++) { if (mixer->channels[i].updateCallback != NULL) { chBuff[i] = mixer->channels[i].updateCallback(mixer->channels[i].ref, count); } else { chBuff[i] = NULL; } } if (mixer->stereo) { while (count--) { Int32 left = 0; Int32 right = 0; for (i = 0; i < mixer->channelCount; i++) { Int32 chanLeft; Int32 chanRight; if (chBuff[i] == NULL) { continue; } if (mixer->channels[i].stereo) { chanLeft = mixer->channels[i].volumeLeft * *chBuff[i]++; chanRight = mixer->channels[i].volumeRight * *chBuff[i]++; } else { Int32 tmp = *chBuff[i]++; chanLeft = mixer->channels[i].volumeLeft * tmp; chanRight = mixer->channels[i].volumeRight * tmp; } mixer->channels[i].volCntLeft += (chanLeft > 0 ? chanLeft : -chanLeft) / 2048; mixer->channels[i].volCntRight += (chanRight > 0 ? chanRight : -chanRight) / 2048; left += chanLeft; right += chanRight; } left /= 4096; right /= 4096; mixer->volCntLeft += left > 0 ? left : -left; mixer->volCntRight += right > 0 ? right : -right; if (left > 32767) { left = 32767; } if (left < -32767) { left = -32767; } if (right > 32767) { right = 32767; } if (right < -32767) { right = -32767; } buffer[mixer->index++] = (Int16)left; buffer[mixer->index++] = (Int16)right; if (mixer->index == mixer->fragmentSize) { if (mixer->writeCallback != NULL) { mixer->writeCallback(mixer->writeRef, buffer, mixer->fragmentSize); } if (mixer->logging) { fwrite(buffer, 2 * mixer->fragmentSize, 1, mixer->file); } mixer->index = 0; } mixer->volIndex++; } } else { while (count--) { Int32 left = 0; for (i = 0; i < mixer->channelCount; i++) { Int32 chanLeft; if (chBuff[i] == NULL) { continue; } if (mixer->channels[i].stereo) { Int32 tmp = *chBuff[i]++; chanLeft = mixer->channels[i].volumeLeft * (tmp + *chBuff[i]++) / 2; } else { chanLeft = mixer->channels[i].volumeLeft * *chBuff[i]++; } mixer->channels[i].volCntLeft += (chanLeft > 0 ? chanLeft : -chanLeft) / 2048; mixer->channels[i].volCntRight += (chanLeft > 0 ? chanLeft : -chanLeft) / 2048; left += chanLeft; } left /= 4096; mixer->volCntLeft += left > 0 ? left : -left; mixer->volCntRight += left > 0 ? left : -left; if (left > 32767) left = 32767; if (left < -32767) left = -32767; buffer[mixer->index++] = (Int16)left; if (mixer->index == mixer->fragmentSize) { if (mixer->writeCallback != NULL) { mixer->writeCallback(mixer->writeRef, buffer, mixer->fragmentSize); } if (mixer->logging) { fwrite(buffer, 2 * mixer->fragmentSize, 1, mixer->file); } mixer->index = 0; } mixer->volIndex++; } } if (mixer->volIndex >= 441) { Int32 newVolumeLeft = mixer->volCntLeft / mixer->volIndex / 164; Int32 newVolumeRight = mixer->volCntRight / mixer->volIndex / 164; if (newVolumeLeft > 100) { newVolumeLeft = 100; } if (newVolumeLeft > mixer->volIntLeft) { mixer->volIntLeft = newVolumeLeft; } if (newVolumeRight > 100) { newVolumeRight = 100; } if (newVolumeRight > mixer->volIntRight) { mixer->volIntRight = newVolumeRight; } mixer->volCntLeft = 0; mixer->volCntRight = 0; for (i = 0; i < mixer->channelCount; i++) { Int32 newVolumeLeft = (Int32)(mixer->channels[i].volCntLeft / mixer->masterVolume / mixer->volIndex / 328); Int32 newVolumeRight = (Int32)(mixer->channels[i].volCntRight / mixer->masterVolume / mixer->volIndex / 328); if (newVolumeLeft > 100) { newVolumeLeft = 100; } if (newVolumeLeft > mixer->channels[i].volIntLeft) { mixer->channels[i].volIntLeft = newVolumeLeft; } if (newVolumeRight > 100) { newVolumeRight = 100; } if (newVolumeRight > mixer->channels[i].volIntRight) { mixer->channels[i].volIntRight = newVolumeRight; } mixer->channels[i].volCntLeft = 0; mixer->channels[i].volCntRight = 0; if (chBuff[i] && chBuff[i][0]) { mixer->channels[i].active++; } } mixer->volIndex = 0; } }
static void sync(WD2793* wd) { if (wd->step) { const UInt64 timePerStep[4] = { 200, 100, 66, 50 }; UInt32 steps = (UInt32)(timePerStep[wd->regCommand & 3] * (boardSystemTime() - wd->stepTime) / boardFrequency()); while (wd->curStep < steps) { wd->curStep++; if ((wd->regCommand & 0x10) || ((wd->regCommand & 0xe0) == 0x00)) { wd->regTrack += wd->stepDirection; } if (diskEnabled(wd->drive) && ((wd->stepDirection == -1 && wd->diskTrack > 0) || wd->stepDirection == 1)) { wd->diskTrack += wd->stepDirection; } if (wd->regCommand & 0xe0) { wd->intRequest = 1; wd->regStatus &= ~ST_BUSY; wd->step = 0; break; } if (wd->stepDirection == -1 && diskEnabled(wd->drive) && wd->diskTrack == 0) { wd->regTrack = 0; wd->intRequest = 1; wd->regStatus &= ~ST_BUSY; wd->step = 0; break; } if (wd->regTrack == wd->regData) { wd->intRequest = 1; wd->regStatus &= ~ST_BUSY; wd->step = 0; break; } } } }
#include "RomLoader.h" #include "JoystickPort.h" #include <string.h> #include <stdlib.h> #include <time.h> extern void PatchReset(BoardType boardType); static int pendingInt; static int boardType; static Mixer* boardMixer = NULL; static int (*syncToRealClock)(int, int) = NULL; UInt32* boardSysTime; static UInt64 boardSysTime64; static UInt32 oldTime; static UInt32 boardFreq = boardFrequency(); static int fdcTimingEnable = 1; static int fdcActive = 0; static BoardTimer* fdcTimer; static BoardTimer* syncTimer; static BoardTimer* mixerTimer; static BoardTimer* stateTimer; static BoardDeviceInfo* boardDeviceInfo; static Machine* boardMachine; static BoardInfo boardInfo; static UInt32 boardRamSize; static UInt32 boardVramSize; static int boardRunning = 0; static HdType hdType[MAX_HD_COUNT];