See description below

Fix FIFO incaauracys.
Remove extra left shift on SPI1 data after the final bit is in.
Remove old image when last state is deleted.
Set active state to the newest one on save state and update image accordingly.
Set spi1RxOverflowed to false on boot.
Move variables to top of function in mainwindow constructor.
This commit is contained in:
meepingsnesroms
2018-12-27 14:56:01 -08:00
parent 538fd36c08
commit f8baa0eb85
8 changed files with 75 additions and 49 deletions

View File

@@ -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);

View File

@@ -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<QString>& getDebugStrings();
std::vector<uint64_t>& getDuplicateCallCount();

View File

@@ -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)

View File

@@ -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
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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){