bool app::process_events(i_event_processing_context&) { bool didSome = false; try { didSome = pump_messages(); didSome = (do_io(neolib::yield_type::Sleep) || didSome); didSome = (do_process_events() || didSome); rendering_engine().render_now(); } catch (std::exception& e) { if (!halted()) { halt(); std::cerr << "neogfx::app::process_events: terminating with exception: " << e.what() << std::endl; iSurfaceManager->display_error_message(iName.empty() ? "Abnormal Program Termination" : "Abnormal Program Termination - " + iName, std::string("neogfx::app::process_events: terminating with exception: ") + e.what()); std::exit(EXIT_FAILURE); } } catch (...) { if (!halted()) { halt(); std::cerr << "neogfx::app::process_events: terminating with unknown exception" << std::endl; iSurfaceManager->display_error_message(iName.empty() ? "Abnormal Program Termination" : "Abnormal Program Termination - " + iName, "neogfx::app::process_events: terminating with unknown exception"); std::exit(EXIT_FAILURE); } } return didSome; }
/// PerCycle int ClusterFunctional::PerCycle() { if (halted()) { return halted(); } ccache->PerCycle(); // HACK: clock the cores in rotating priority to avoid starvation (should not be any) // OK for FUNCTIONAL simulation, we are not limiting bandwidth or modelling contention int idx = rigel::CURR_CYCLE % numcores; int halted_cores = 0; for (int offset = 0; offset < numcores; offset++) { halted_cores += cores[idx]->PerCycle(); idx = (idx + 1) % numcores; } halted_ = halted_cores; if (halted()) { printf("all %d cores halted in cluster %d\n", numcores, id()); } return halted(); };
/// called each cycle /// update all owned components int TileNew::PerCycle() { if( halted() ) { return halted(); } interconnect->PerCycle(); int idx = rigel::CURR_CYCLE % rigel::CLUSTERS_PER_TILE; int halted_clusters = 0; for (int offset = 0; offset < rigel::CLUSTERS_PER_TILE; offset++) { halted_clusters += clusters[idx]->PerCycle(); idx = (idx + 1) % rigel::CLUSTERS_PER_TILE; } _halted = halted_clusters; return halted(); }
bool io_thread::pump_messages() { bool didWork = false; while (have_messages()) { if (halted()) return didWork; if (have_message_queue()) { message_queue().get_message(); message_queue().idle(); } didWork = true; } return didWork; }
unsigned long Memory::event(unsigned long cycleCounter) { if (lastOamDmaUpdate != DISABLED_TIME) updateOamDma(cycleCounter); switch (intreq.minEventId()) { case UNHALT: nontrivial_ff_write(0xFF04, 0, cycleCounter); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; intreq.unhalt(); intreq.setEventTime<UNHALT>(DISABLED_TIME); break; case END: intreq.setEventTime<END>(DISABLED_TIME - 1); while (cycleCounter >= intreq.minEventTime() && intreq.eventTime(END) != DISABLED_TIME) cycleCounter = event(cycleCounter); intreq.setEventTime<END>(DISABLED_TIME); break; case BLIT: { const bool lcden = ioamhram[0x140] >> 7 & 1; unsigned long blitTime = intreq.eventTime(BLIT); if (lcden | blanklcd) { display.updateScreen(blanklcd, cycleCounter); intreq.setEventTime<BLIT>(DISABLED_TIME); intreq.setEventTime<END>(DISABLED_TIME); while (cycleCounter >= intreq.minEventTime()) cycleCounter = event(cycleCounter); } else blitTime += 70224 << isDoubleSpeed(); blanklcd = lcden ^ 1; intreq.setEventTime<BLIT>(blitTime); } break; case SERIAL: updateSerial(cycleCounter); break; case OAM: intreq.setEventTime<OAM>(lastOamDmaUpdate == DISABLED_TIME ? static_cast<unsigned long>(DISABLED_TIME) : intreq.eventTime(OAM) + 0xA0 * 4); break; case DMA: { const bool doubleSpeed = isDoubleSpeed(); unsigned dmaSrc = dmaSource; unsigned dmaDest = dmaDestination; unsigned dmaLength = ((ioamhram[0x155] & 0x7F) + 0x1) * 0x10; unsigned length = hdmaReqFlagged(intreq) ? 0x10 : dmaLength; ackDmaReq(&intreq); if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) { length = 0x10000 - dmaDest; ioamhram[0x155] |= 0x80; } dmaLength -= length; if (!(ioamhram[0x140] & 0x80)) dmaLength = 0; { unsigned long lOamDmaUpdate = lastOamDmaUpdate; lastOamDmaUpdate = DISABLED_TIME; while (length--) { const unsigned src = dmaSrc++ & 0xFFFF; const unsigned data = ((src & 0xE000) == 0x8000 || src > 0xFDFF) ? 0xFF : read(src, cycleCounter); cycleCounter += 2 << doubleSpeed; if (cycleCounter - 3 > lOamDmaUpdate) { oamDmaPos = (oamDmaPos + 1) & 0xFF; lOamDmaUpdate += 4; if (oamDmaPos < 0xA0) { if (oamDmaPos == 0) startOamDma(lOamDmaUpdate - 1); ioamhram[src & 0xFF] = data; } else if (oamDmaPos == 0xA0) { endOamDma(lOamDmaUpdate - 1); lOamDmaUpdate = DISABLED_TIME; } } nontrivial_write(0x8000 | (dmaDest++ & 0x1FFF), data, cycleCounter); } lastOamDmaUpdate = lOamDmaUpdate; } cycleCounter += 4; dmaSource = dmaSrc; dmaDestination = dmaDest; ioamhram[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram[0x155] & 0x80); if ((ioamhram[0x155] & 0x80) && display.hdmaIsEnabled()) { if (lastOamDmaUpdate != DISABLED_TIME) updateOamDma(cycleCounter); display.disableHdma(cycleCounter); } } break; case TIMA: tima.doIrqEvent(TimaInterruptRequester(intreq)); break; case VIDEO: display.update(cycleCounter); break; case INTERRUPTS: if (stopped) { intreq.setEventTime<INTERRUPTS>(DISABLED_TIME); break; } if (halted()) { if (gbIsCgb_ || (!gbIsCgb_ && cycleCounter <= halttime + 4)) cycleCounter += 4; intreq.unhalt(); intreq.setEventTime<UNHALT>(DISABLED_TIME); } if (ime()) { unsigned address; cycleCounter += 12; display.update(cycleCounter); SP = (SP - 2) & 0xFFFF; write(SP + 1, PC >> 8, cycleCounter); unsigned ie = intreq.iereg(); cycleCounter += 4; display.update(cycleCounter); write(SP, PC & 0xFF, cycleCounter); const unsigned pendingIrqs = ie & intreq.ifreg(); cycleCounter += 4; display.update(cycleCounter); const unsigned n = pendingIrqs & -pendingIrqs; if (n == 0) { address = 0; } else if (n < 8) { static const unsigned char lut[] = { 0x40, 0x48, 0x48, 0x50 }; address = lut[n-1]; } else address = 0x50 + n; intreq.ackIrq(n); PC = address; } break; } return cycleCounter; }
void InterruptRequester::saveState(SaveState &state) const { state.mem.minIntTime = minIntTime; state.mem.IME = ime(); state.mem.halted = halted(); }
void Clock::trigger() { if (!halt) emit tick(); if ((halt = newHalt)) emit halted(); }
unsigned long Memory::event(unsigned long cc) { if (lastOamDmaUpdate_ != disabled_time) updateOamDma(cc); switch (intreq_.minEventId()) { case intevent_unhalt: intreq_.unhalt(); intreq_.setEventTime<intevent_unhalt>(disabled_time); break; case intevent_end: intreq_.setEventTime<intevent_end>(disabled_time - 1); while (cc >= intreq_.minEventTime() && intreq_.eventTime(intevent_end) != disabled_time) { cc = event(cc); } intreq_.setEventTime<intevent_end>(disabled_time); break; case intevent_blit: { bool const lcden = ioamhram_[0x140] & lcdc_en; unsigned long blitTime = intreq_.eventTime(intevent_blit); if (lcden | blanklcd_) { lcd_.updateScreen(blanklcd_, cc); intreq_.setEventTime<intevent_blit>(disabled_time); intreq_.setEventTime<intevent_end>(disabled_time); while (cc >= intreq_.minEventTime()) cc = event(cc); } else blitTime += 70224 << isDoubleSpeed(); blanklcd_ = lcden ^ 1; intreq_.setEventTime<intevent_blit>(blitTime); } break; case intevent_serial: updateSerial(cc); break; case intevent_oam: intreq_.setEventTime<intevent_oam>(lastOamDmaUpdate_ == disabled_time ? static_cast<unsigned long>(disabled_time) : intreq_.eventTime(intevent_oam) + 0xA0 * 4); break; case intevent_dma: { bool const doubleSpeed = isDoubleSpeed(); unsigned dmaSrc = dmaSource_; unsigned dmaDest = dmaDestination_; unsigned dmaLength = ((ioamhram_[0x155] & 0x7F) + 0x1) * 0x10; unsigned length = hdmaReqFlagged(intreq_) ? 0x10 : dmaLength; ackDmaReq(intreq_); if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) { length = 0x10000 - dmaDest; ioamhram_[0x155] |= 0x80; } dmaLength -= length; if (!(ioamhram_[0x140] & lcdc_en)) dmaLength = 0; { unsigned long lOamDmaUpdate = lastOamDmaUpdate_; lastOamDmaUpdate_ = disabled_time; while (length--) { unsigned const src = dmaSrc++ & 0xFFFF; unsigned const data = (src & 0xE000) == 0x8000 || src > 0xFDFF ? 0xFF : read(src, cc); cc += 2 << doubleSpeed; if (cc - 3 > lOamDmaUpdate) { oamDmaPos_ = (oamDmaPos_ + 1) & 0xFF; lOamDmaUpdate += 4; if (oamDmaPos_ < 0xA0) { if (oamDmaPos_ == 0) startOamDma(lOamDmaUpdate - 1); ioamhram_[src & 0xFF] = data; } else if (oamDmaPos_ == 0xA0) { endOamDma(lOamDmaUpdate - 1); lOamDmaUpdate = disabled_time; } } nontrivial_write(0x8000 | (dmaDest++ & 0x1FFF), data, cc); } lastOamDmaUpdate_ = lOamDmaUpdate; } cc += 4; dmaSource_ = dmaSrc; dmaDestination_ = dmaDest; ioamhram_[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram_[0x155] & 0x80); if ((ioamhram_[0x155] & 0x80) && lcd_.hdmaIsEnabled()) { if (lastOamDmaUpdate_ != disabled_time) updateOamDma(cc); lcd_.disableHdma(cc); } } break; case intevent_tima: tima_.doIrqEvent(TimaInterruptRequester(intreq_)); break; case intevent_video: lcd_.update(cc); break; case intevent_interrupts: if (halted()) { if (isCgb()) cc += 4; intreq_.unhalt(); intreq_.setEventTime<intevent_unhalt>(disabled_time); } if (ime()) { unsigned const pendingIrqs = intreq_.pendingIrqs(); unsigned const n = pendingIrqs & -pendingIrqs; unsigned address; if (n <= 4) { static unsigned char const lut[] = { 0x40, 0x48, 0x48, 0x50 }; address = lut[n-1]; } else address = 0x50 + n; intreq_.ackIrq(n); cc = interrupter_.interrupt(address, cc, *this); } break; } return cc; }