diff --git a/qtBuildSystem/Mu/emuwrapper.cpp b/qtBuildSystem/Mu/emuwrapper.cpp index d815040..d274e2b 100644 --- a/qtBuildSystem/Mu/emuwrapper.cpp +++ b/qtBuildSystem/Mu/emuwrapper.cpp @@ -316,7 +316,7 @@ uint32_t EmuWrapper::loadState(const QString& path){ return error; } -uint32_t EmuWrapper::installApplication(QString path){ +uint32_t EmuWrapper::installApplication(const QString& path){ bool wasPaused = isPaused(); uint32_t error = EMU_ERROR_INVALID_PARAMETER; QFile appFile(path); diff --git a/qtBuildSystem/Mu/emuwrapper.h b/qtBuildSystem/Mu/emuwrapper.h index 432c2ee..c68f92d 100644 --- a/qtBuildSystem/Mu/emuwrapper.h +++ b/qtBuildSystem/Mu/emuwrapper.h @@ -43,7 +43,7 @@ public: bool isRunning() const{return emuRunning;} bool isPaused() const{return emuPaused;} - uint32_t installApplication(QString path); + uint32_t installApplication(const QString& path); std::vector& getDebugStrings(); std::vector& getDuplicateCallCount(); diff --git a/qtBuildSystem/Mu/mainwindow.cpp b/qtBuildSystem/Mu/mainwindow.cpp index d23ae94..27e08c0 100644 --- a/qtBuildSystem/Mu/mainwindow.cpp +++ b/qtBuildSystem/Mu/mainwindow.cpp @@ -53,9 +53,10 @@ void printLastRun(){ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow){ - ui->setupUi(this); - QAudioFormat format; + QString resourceDirPath; + + //audio output format.setSampleRate(AUDIO_SAMPLE_RATE); format.setChannelCount(2); format.setSampleSize(16); @@ -67,6 +68,7 @@ MainWindow::MainWindow(QWidget* parent) : #endif format.setSampleType(QAudioFormat::SignedInt); + //submodules settings = new QSettings(QDir::homePath() + "/MuCfg.txt", QSettings::IniFormat);//settings is public, create it first stateManager = new StateManager(this); emuDebugger = new DebugViewer(this); @@ -74,6 +76,27 @@ MainWindow::MainWindow(QWidget* parent) : audioDevice = new QAudioOutput(format, this); audioOut = audioDevice->start(); + //resource directory + resourceDirPath = settings->value("resourceDirectory", "").toString(); + + //get default path if path not set + if(resourceDirPath == ""){ +#if defined(Q_OS_ANDROID) + resourceDirPath = "/sdcard/Mu"; +#elif defined(Q_OS_IOS) + resourceDirPath = "/var/mobile/Media/Mu"; +#else + resourceDirPath = QDir::homePath() + "/Mu"; +#endif + settings->setValue("resourceDirectory", resourceDirPath); + } + + //create directory tree, in case someone deleted it since the emu was last run or it was never created + createHomeDirectoryTree(resourceDirPath); + + //GUI + ui->setupUi(this); + //this makes the display window and button icons resize properly ui->centralWidget->installEventFilter(this); ui->centralWidget->setObjectName("centralWidget"); @@ -97,29 +120,9 @@ MainWindow::MainWindow(QWidget* parent) : ui->screenshot->installEventFilter(this); ui->stateManager->installEventFilter(this); - - QString resourceDirPath = settings->value("resourceDirectory", "").toString(); - - //use default path if path not set - if(resourceDirPath == ""){ -#if defined(Q_OS_ANDROID) - resourceDirPath = "/sdcard/Mu"; -#elif defined(Q_OS_IOS) - resourceDirPath = "/var/mobile/Media/Mu"; -#else - resourceDirPath = QDir::homePath() + "/Mu"; -#endif - settings->setValue("resourceDirectory", resourceDirPath); - } - - //create directory tree, in case someone deleted it since the emu was last run - createHomeDirectoryTree(resourceDirPath); - - #if !defined(EMU_DEBUG) || defined(Q_OS_ANDROID) || defined(Q_OS_IOS) ui->debugger->hide(); #endif - connect(refreshDisplay, SIGNAL(timeout()), this, SLOT(updateDisplay())); refreshDisplay->start(1000 / EMU_FPS);//update display every X milliseconds } @@ -372,7 +375,6 @@ void MainWindow::on_stateManager_clicked(){ if(!wasPaused) emu.pause(); - stateManager->updateStateList(); stateManager->exec(); if(!wasPaused) diff --git a/qtBuildSystem/Mu/statemanager.cpp b/qtBuildSystem/Mu/statemanager.cpp index 2bfab5f..d03879c 100644 --- a/qtBuildSystem/Mu/statemanager.cpp +++ b/qtBuildSystem/Mu/statemanager.cpp @@ -20,12 +20,21 @@ StateManager::StateManager(QWidget* parent) : //this allows resizing the screenshot of the savestate ui->statePreview->installEventFilter(this); ui->statePreview->setObjectName("statePreview"); + + updateStateList(); } StateManager::~StateManager(){ delete ui; } +bool StateManager::eventFilter(QObject* object, QEvent* event){ + if(object->objectName() == "statePreview" && event->type() == QEvent::Resize) + updateStatePreview(); + + return QDialog::eventFilter(object, event); +} + void StateManager::updateStateList(){ MainWindow* parent = (MainWindow*)parentWidget(); QString saveDirPath = parent->settings->value("resourceDirectory", "").toString() + "/saveStates"; @@ -47,21 +56,27 @@ void StateManager::updateStateList(){ } } -bool StateManager::eventFilter(QObject* object, QEvent* event){ - if(object->objectName() == "statePreview" && event->type() == QEvent::Resize) - updateStatePreview(); - - return QDialog::eventFilter(object, event); -} - void StateManager::updateStatePreview(){ if(ui->states->currentItem()){ MainWindow* parent = (MainWindow*)parentWidget(); QString statePath = parent->settings->value("resourceDirectory", "").toString() + "/saveStates/" + ui->states->currentItem()->text(); ui->statePreview->setPixmap(QPixmap(statePath + ".png").scaled(ui->statePreview->width() * 0.98, ui->statePreview->height() * 0.98, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - ui->statePreview->update(); } + else{ + //remove outdated image + ui->statePreview->clear(); + } + + ui->statePreview->update(); +} + +int StateManager::getStateIndexRowByName(const QString& name){ + for(int index = 0; index < ui->states->count(); index++) + if(ui->states->item(index)->text() == name) + return index; + + return -1;//nothing by that name exists } void StateManager::on_saveState_clicked(){ @@ -72,6 +87,8 @@ void StateManager::on_saveState_clicked(){ parent->emu.saveState(statePath + ".state"); parent->emu.getFramebuffer().save(statePath + ".png"); updateStateList(); + + ui->states->setCurrentRow(getStateIndexRowByName(ui->newStateName->text()));//this also updates the preview image } } @@ -92,6 +109,7 @@ void StateManager::on_deleteState_clicked(){ QFile(statePath + ".state").remove(); QFile(statePath + ".png").remove(); updateStateList(); + ui->states->setCurrentRow(0);//pick first valid entry since the old one is no longer valid } } diff --git a/qtBuildSystem/Mu/statemanager.h b/qtBuildSystem/Mu/statemanager.h index b3758e4..95834b1 100644 --- a/qtBuildSystem/Mu/statemanager.h +++ b/qtBuildSystem/Mu/statemanager.h @@ -16,12 +16,12 @@ public: explicit StateManager(QWidget* parent = nullptr); ~StateManager(); - void updateStateList(); - private slots: bool eventFilter(QObject* object, QEvent* event); + void updateStateList(); void updateStatePreview(); + int getStateIndexRowByName(const QString& name); void on_saveState_clicked(); void on_loadState_clicked(); diff --git a/src/hardwareRegisters.c b/src/hardwareRegisters.c index 6fc6806..4caf73d 100644 --- a/src/hardwareRegisters.c +++ b/src/hardwareRegisters.c @@ -434,6 +434,7 @@ uint16_t getHwRegister16(uint32_t address){ uint16_t fifoVal = spi1RxFifoRead(); //check if SPI1 interrupts changed setSpiIntCs(registerArrayRead16(SPIINTCS)); + debugLog("SPIRXD read, FIFO value:0x%04X, SPIINTCS:0x%04X\n", fifoVal, registerArrayRead16(SPIINTCS)); return fifoVal; } @@ -1020,6 +1021,7 @@ void resetHwRegisters(void){ memset(spi1TxFifo, 0x00, sizeof(spi1TxFifo)); spi1RxReadPosition = 0; spi1RxWritePosition = 0; + spi1RxOverflowed = false; spi1TxReadPosition = 0; spi1TxWritePosition = 0; pwm1ClocksToNextSample = 0; diff --git a/src/hardwareRegistersAccessors.c.h b/src/hardwareRegistersAccessors.c.h index fdb3495..1fa759f 100644 --- a/src/hardwareRegistersAccessors.c.h +++ b/src/hardwareRegistersAccessors.c.h @@ -40,21 +40,22 @@ static uint8_t spi1RxFifoEntrys(void){ } static uint16_t spi1RxFifoRead(void){ - uint16_t value = spi1RxFifo[spi1RxReadPosition]; if(spi1RxFifoEntrys() > 0) spi1RxReadPosition = (spi1RxReadPosition + 1) % 9; spi1RxOverflowed = false; - return value; + + return spi1RxFifo[spi1RxReadPosition]; } static void spi1RxFifoWrite(uint16_t value){ if(spi1RxFifoEntrys() < 8){ spi1RxWritePosition = (spi1RxWritePosition + 1) % 9; - spi1RxFifo[spi1RxWritePosition] = value; } else{ spi1RxOverflowed = true; + debugLog("SPI1 RX FIFO overflowed\n"); } + spi1RxFifo[spi1RxWritePosition] = value; } static void spi1RxFifoFlush(void){ @@ -69,10 +70,9 @@ static uint8_t spi1TxFifoEntrys(void){ } static uint16_t spi1TxFifoRead(void){ - uint16_t value = spi1TxFifo[spi1TxReadPosition]; //dont need a safety check here, the emulator will always check that data is present before trying to access it spi1TxReadPosition = (spi1TxReadPosition + 1) % 9; - return value; + return spi1TxFifo[spi1TxReadPosition]; } static void spi1TxFifoWrite(uint16_t value){ @@ -95,7 +95,6 @@ static uint8_t pwm1FifoEntrys(void){ } int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){ - uint8_t sample = pwm1Fifo[pwm1ReadPosition]; uint16_t period = registerArrayRead8(PWMP1) + 2; uint16_t pwmc1 = registerArrayRead16(PWMC1); uint8_t prescaler = (pwmc1 >> 8 & 0x7F) + 1; @@ -103,9 +102,14 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){ uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03); int32_t audioNow = now + clockOffset; int32_t audioSampleDuration = (pwmc1 & 0x8000)/*CLKSRC*/ ? audioGetFramePercentIncrementFromClk32s(period * prescaler * clockDivider) : audioGetFramePercentIncrementFromSysclks(period * prescaler * clockDivider); - float dutyCycle = fMin((float)sample / period, 1.00); + float dutyCycle; uint8_t index; + //try to get next sample, if none are available play old sample + if(pwm1FifoEntrys() > 0) + pwm1ReadPosition = (pwm1ReadPosition + 1) % 6; + dutyCycle = fMin((float)pwm1Fifo[pwm1ReadPosition] / period, 1.00); + for(index = 0; index < repeat; index++){ #if !defined(EMU_NO_SAFETY) if(audioNow + audioSampleDuration >= AUDIO_CLOCK_RATE) @@ -117,10 +121,6 @@ int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){ audioNow += audioSampleDuration; } - //remove used entry - if(pwm1FifoEntrys() > 0) - pwm1ReadPosition = (pwm1ReadPosition + 1) % 6; - //check for interrupt if(pwm1FifoEntrys() < 2){ //trigger interrupt if enabled @@ -336,7 +336,7 @@ static void setSpiIntCs(uint16_t value){ newSpiIntCs |= (rxEntrys >= 4) << 4;//RH newSpiIntCs |= (rxEntrys > 0) << 3;//RR newSpiIntCs |= (txEntrys == 8) << 2;//TF - newSpiIntCs |= (txEntrys >= 4) << 1;//TH + newSpiIntCs |= (txEntrys >= 4) << 1;//TH, the datasheet contradicts itself on whether its more than or equal to 4 empty or full slots newSpiIntCs |= txEntrys == 0;//TE //if interrupt state changed update interrupts too, top 8 bits are just the enable bits for the bottom 8 @@ -358,7 +358,7 @@ static void setSpiCont1(uint16_t value){ //debugLog("SPICONT1 write, old value:0x%04X, value:0x%04X\n", oldSpiCont1, value); //SPI1 disabled - if(oldSpiCont1 & 0x0200 && !(value & 0x2000)){ + if(oldSpiCont1 & 0x0200 && !(value & 0x0200)){ spi1RxFifoFlush(); spi1TxFifoFlush(); } @@ -380,8 +380,8 @@ static void setSpiCont1(uint16_t value){ //The most significant bit is output when the CPU loads the transmitted data, 13.2.3 SPI 1 Phase and Polarity Configurations MC68VZ328UM.pdf for(bits = 0; bits < bitCount; bits++){ - newRxFifoEntry |= sdCardExchangeBit(!!(currentTxFifoEntry & startBit)); newRxFifoEntry <<= 1; + newRxFifoEntry |= sdCardExchangeBit(!!(currentTxFifoEntry & startBit)); currentTxFifoEntry <<= 1; } @@ -398,6 +398,8 @@ static void setSpiCont1(uint16_t value){ //update SPIINTCS interrupt bits setSpiIntCs(registerArrayRead16(SPIINTCS)); + debugLog("Transfer complete, SPIINTCS:0x%04X\n", registerArrayRead16(SPIINTCS)); + registerArrayWrite16(SPICONT1, value); } diff --git a/src/sdCard.c b/src/sdCard.c index c5ed9c2..f0495c2 100644 --- a/src/sdCard.c +++ b/src/sdCard.c @@ -67,6 +67,7 @@ static void sdCardDoResponseR1(uint8_t r1){ palmSdCard.response = SD_CARD_RESPONSE_SHIFT_OUT; palmSdCard.responseState = (uint64_t)r1 << 56; palmSdCard.responseState |= (uint64_t)1 << 55;//add shift termination bit + //palmSdCard.responseState >>= 8; } static void sdCardDoResponseR3(uint8_t r1){ @@ -74,6 +75,7 @@ static void sdCardDoResponseR3(uint8_t r1){ palmSdCard.responseState = (uint64_t)r1 << 56; palmSdCard.responseState |= (uint64_t)sdCardOcr << 24; palmSdCard.responseState |= (uint64_t)1 << 23;//add shift termination bit + //palmSdCard.responseState >>= 8; } void sdCardReset(void){