Skip to content

Commit

Permalink
Fast Emulation Toggle and various debugger/misc fixes (#142)
Browse files Browse the repository at this point in the history
* Remove C02C unimpl access warning
* change fast emulation fps thresholds
* Hot keys and menu items for pause/continue, mouse lock and debugger toggle
* fast mode toggle
* User directory as the default file browser directory
* Remove damping of ensoniq audio
* fix disk switching for 3.5 disks when mounting without ejecting
* Added IRQ mask debug and cleaned up address parsing in debugger
* Welcome text for 0.6 changed, placeholder print memory and save powered-on status on app shutdown
  • Loading branch information
samkusin authored Aug 15, 2023
1 parent 7fc5a4a commit 502b838
Show file tree
Hide file tree
Showing 24 changed files with 528 additions and 89 deletions.
3 changes: 2 additions & 1 deletion clem_audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,12 @@ unsigned clem_ensoniq_voices(struct ClemensDeviceEnsoniq *doc) {
// down convert voices output into 2 channel mono
void clem_ensoniq_mono(struct ClemensDeviceEnsoniq *doc, unsigned osc_max_channels, float *left,
float *right) {
unsigned active_osc = 0;
*left = 0.0f;
*right = 0.0f;

for (unsigned channel_idx = 0; channel_idx < osc_max_channels; ++channel_idx) {
*left += (doc->voice[channel_idx] * 0.50f);
*left += doc->voice[channel_idx];
}
if (*left > 1.0f)
*left = 1.0f;
Expand Down
3 changes: 3 additions & 0 deletions clem_drive35.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ int clem_disk_control_35(struct ClemensDrive *drive, unsigned *io_flags, unsigne
CLEM_DEBUG("clem_drive35: step to outward tracks");
break;
case CLEM_IWM_DISK35_CTL_EJECTED_RESET:
if (drive->status_mask_35 & CLEM_IWM_DISK35_STATUS_EJECTED) {
CLEM_LOG("clem_drive35: clearing eject status");
}
drive->status_mask_35 &= ~CLEM_IWM_DISK35_STATUS_EJECTED;
break;
case CLEM_IWM_DISK35_CTL_STEP_ONE:
Expand Down
9 changes: 5 additions & 4 deletions clem_iwm.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ struct ClemensNibbleDisk *clem_iwm_eject_disk(struct ClemensDeviceIWM *iwm,
return NULL;

if (drive->disk.disk_type == CLEM_DISK_TYPE_3_5) {
drive->status_mask_35 &=
~(CLEM_IWM_DISK35_STATUS_EJECTING | CLEM_IWM_DISK35_STATUS_EJECTED);
drive->status_mask_35 &= ~(CLEM_IWM_DISK35_STATUS_EJECTING);
drive->status_mask_35 |= CLEM_IWM_DISK35_STATUS_EJECTED;
}
drive->has_disk = false;
return &drive->disk;
Expand All @@ -295,9 +295,10 @@ unsigned clem_iwm_eject_disk_in_progress(struct ClemensDeviceIWM *iwm, struct Cl
if (drive->disk.disk_type == CLEM_DISK_TYPE_3_5) {
if (drive->status_mask_35 & CLEM_IWM_DISK35_STATUS_EJECTING)
return CLEM_EJECT_DISK_STATUS_IN_PROGRESS;
if (drive->status_mask_35 & CLEM_IWM_DISK35_STATUS_EJECTED)
return CLEM_EJECT_DISK_STATUS_EJECTED;
}
} else {
if (drive->status_mask_35 & CLEM_IWM_DISK35_STATUS_EJECTED)
return CLEM_EJECT_DISK_STATUS_EJECTED;
}
return CLEM_EJECT_DISK_STATUS_NONE;
}
Expand Down
6 changes: 6 additions & 0 deletions clem_mmio.c
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,9 @@ uint8_t clem_mmio_read(ClemensMMIO *mmio, struct ClemensTimeSpec *tspec, uint16_
case CLEM_MMIO_REG_LANGSEL:
result = clem_vgc_get_region(&mmio->vgc);
break;
case CLEM_MMIO_REG_CHARROM_TEST:
result = 0x00; // TODO: unsure what to do unless we store the character ROM in memory vs font files
break;
case CLEM_MMIO_REG_SLOTROMSEL:
result = _clem_mmio_slotromsel_c02d(mmio);
*mega2_access = false;
Expand Down Expand Up @@ -1073,6 +1076,9 @@ void clem_mmio_write(ClemensMMIO *mmio, struct ClemensTimeSpec *tspec, uint8_t d
case CLEM_MMIO_REG_LANGSEL:
clem_vgc_set_region(&mmio->vgc, data);
break;
case CLEM_MMIO_REG_CHARROM_TEST:
// NO-OP - avoid the unimpl warning if done as a 16-bit write to LANGSEL
break;
case CLEM_MMIO_REG_SLOTROMSEL:
_clem_mmio_slotrom_select_c02d(mmio, data);
break;
Expand Down
25 changes: 18 additions & 7 deletions host/clem_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ void ClemensRunSampler::reset() {
sampledCyclesSpent = 0;
sampledFramesPerSecond = 0.0f;
sampledMachineSpeedMhz = 0.0f;
sampledEmulationSpeedMhz = 0.0f;
avgVBLsPerFrame = 0.0f;
sampledVblsSpent = 0;
emulatorVblsPerFrame = 1;
Expand Down Expand Up @@ -136,6 +137,8 @@ void ClemensRunSampler::update(clem_clocks_duration_t clocksSpent, unsigned cycl
sampledMachineSpeedMhz = 1.023 * cyclesPerClock * CLEM_CLOCKS_PHI0_CYCLE;
}

sampledEmulationSpeedMhz = sampledCyclesSpent / double(sampledFrameTime.count());

if (vblsBuffer.isFull()) {
decltype(vblsBuffer)::ValueType lruVbls = 0;
vblsBuffer.pop(lruVbls);
Expand All @@ -144,11 +147,9 @@ void ClemensRunSampler::update(clem_clocks_duration_t clocksSpent, unsigned cycl
vblsBuffer.push(emulatorVblsPerFrame);
sampledVblsSpent += emulatorVblsPerFrame;
if (fastModeEnabled) {
if (sampledFramesPerSecond > 45.0) {
if (sampledFramesPerSecond > 15.0) {
emulatorVblsPerFrame += 1;
} else if (sampledFramesPerSecond < 35.0) {
emulatorVblsPerFrame -= 1;
}
}
if (emulatorVblsPerFrame < 1)
emulatorVblsPerFrame = 1;

Expand All @@ -163,8 +164,8 @@ ClemensBackend::ClemensBackend(std::string romPath, const Config &config)
interpreterData_(kInterpreterMemorySize),
interpreter_(cinek::FixedStack(kInterpreterMemorySize, interpreterData_.data())),
breakpoints_(std::move(config_.breakpoints)), logLevel_(config_.logLevel),
debugMemoryPage_(0x00), areInstructionsLogged_(false), stepsRemaining_(0),
clocksRemainingInTimeslice_(0) {
debugMemoryPage_(0x00), areInstructionsLogged_(false), fastModeEnabled_(false),
stepsRemaining_(0), clocksRemainingInTimeslice_(0) {

loggedInstructions_.reserve(10000);

Expand Down Expand Up @@ -225,7 +226,7 @@ auto ClemensBackend::step(ClemensCommandQueue &commands) -> ClemensCommandQueue:
// Though if the emulator runs hot (cannot execute the desired cycles in enough time),
// that shouldn't matter too much given that this 'speed boost' is meant to be
// temporary, and the emulator should catch up once the IWM is inactive.
if (clemens_is_drive_io_active(&GS_->getMMIO()) && config_.enableFastEmulation) {
if ((clemens_is_drive_io_active(&GS_->getMMIO()) && config_.enableFastEmulation) || fastModeEnabled_) {
runSampler_.enableFastMode();
} else {
runSampler_.disableFastMode();
Expand Down Expand Up @@ -344,8 +345,10 @@ void ClemensBackend::post(ClemensBackendState &backendState) {
}
backendState.debugMemoryPage = debugMemoryPage_;
backendState.machineSpeedMhz = runSampler_.sampledMachineSpeedMhz;
backendState.emulationSpeedMhz = runSampler_.sampledEmulationSpeedMhz;
backendState.avgVBLsPerFrame = runSampler_.avgVBLsPerFrame;
backendState.fastEmulationOn = runSampler_.emulatorVblsPerFrame > 1;
backendState.fastModeEnabled = fastModeEnabled_;

GS_->finishFrame(backendState.frame);
hitBreakpoint_ = std::nullopt;
Expand Down Expand Up @@ -741,6 +744,10 @@ bool ClemensBackend::onCommandDebugProgramTrace(std::string_view op, std::string
return ok;
}

void ClemensBackend::onCommandDebugMemoryPrint(unsigned /*address */, unsigned /* count */) {
// TODO
}

bool ClemensBackend::onCommandSaveMachine(std::string path, std::unique_ptr<ClemensCommandMinizPNG> pngData) {
auto outputPath = std::filesystem::path(config_.snapshotRootPath) / path;

Expand Down Expand Up @@ -919,3 +926,7 @@ bool ClemensBackend::onCommandBinarySave(std::string pathname, unsigned address,
localLog(CLEM_DEBUG_LOG_INFO, "Saved {} bytes to '{}'.", length, pathname);
return true;
}

void ClemensBackend::onCommandFastMode(bool enabled) {
fastModeEnabled_ = enabled;
}
8 changes: 8 additions & 0 deletions host/clem_backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ struct ClemensRunSampler {
cinek::CircularBuffer<clem_clocks_duration_t, 60> clocksBuffer;
cinek::CircularBuffer<clem_clocks_duration_t, 60> cyclesBuffer;

// sampledMachineSpeedMhz is the speed from the machine's perspective (i.e. 2.8mhz is fast)
// sampledEmulationSpeedMhz is the speed from the host's perspective
// sampledEmulationSpeedMhz ~ sampledMachineSpeedMhz when running at NTSC frequency
// sampledEmulationSpeedMhz should be larger when running at full speed
double sampledMachineSpeedMhz;
double sampledEmulationSpeedMhz;
std::chrono::high_resolution_clock::time_point lastFrameTimePoint;

double avgVBLsPerFrame;
Expand Down Expand Up @@ -131,6 +136,7 @@ class ClemensBackend : public ClemensSystemListener, ClemensCommandQueueListener
void onCommandDebugMemoryWrite(uint16_t addr, uint8_t value) final;
void onCommandDebugLogLevel(int logLevel) final;
bool onCommandDebugProgramTrace(std::string_view op, std::string_view path) final;
void onCommandDebugMemoryPrint(unsigned address, unsigned count) final;
bool onCommandSaveMachine(std::string path, std::unique_ptr<ClemensCommandMinizPNG> pngData) final;
bool onCommandLoadMachine(std::string path) final;
bool onCommandRunScript(std::string command) final;
Expand All @@ -139,6 +145,7 @@ class ClemensBackend : public ClemensSystemListener, ClemensCommandQueueListener
void onCommandSendText(std::string msg) final;
bool onCommandBinaryLoad(std::string pathname, unsigned address) final;
bool onCommandBinarySave(std::string pathname, unsigned address, unsigned length) final;
void onCommandFastMode(bool enabled) final;

// internal
bool isRunning() const;
Expand Down Expand Up @@ -172,6 +179,7 @@ class ClemensBackend : public ClemensSystemListener, ClemensCommandQueueListener
bool areInstructionsLogged_;

ClemensRunSampler runSampler_;
bool fastModeEnabled_;

std::optional<int> stepsRemaining_;
int64_t clocksRemainingInTimeslice_;
Expand Down
11 changes: 11 additions & 0 deletions host/clem_command_queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ auto ClemensCommandQueue::dispatchAll(ClemensCommandQueueListener &listener) ->
if (!programTrace(listener, cmd.operand))
commandFailed = true;
break;
case Command::DebugPrintMemory: {
// address, count (parse)
// listener.onCommandDebugMemoryPrint(address, count);
} break;
case Command::SaveMachine:
commandFailed = true;
if (!data || data->getType() == ClemensCommandData::Type::MinizPNG) {
Expand Down Expand Up @@ -169,6 +173,9 @@ auto ClemensCommandQueue::dispatchAll(ClemensCommandQueueListener &listener) ->
commandFailed = true;
}
break;
case Command::FastMode:
listener.onCommandFastMode(cmd.operand == "1");
break;
case Command::Undefined:
break;
}
Expand Down Expand Up @@ -542,6 +549,10 @@ void ClemensCommandQueue::bload(std::string pathname, unsigned address) {
queue(Command{Command::LoadBinary, fmt::format("{},{:x}", pathname, address)});
}

void ClemensCommandQueue::fastMode(bool enable) {
queue(Command{Command::FastMode, enable ? "1" : "0"});
}

void ClemensCommandQueue::queue(const Command &cmd, Data data) {
queue_.push(cmd);
dataQueue_.push(std::move(data));
Expand Down
4 changes: 4 additions & 0 deletions host/clem_command_queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class ClemensCommandQueueListener {
virtual void onCommandDebugMemoryWrite(uint16_t addr, uint8_t value) = 0;
virtual void onCommandDebugLogLevel(int logLevel) = 0;
virtual bool onCommandDebugProgramTrace(std::string_view op, std::string_view path) = 0;
virtual void onCommandDebugMemoryPrint(unsigned address, unsigned count) = 0;
virtual bool onCommandSaveMachine(std::string path,
std::unique_ptr<ClemensCommandMinizPNG> pngData) = 0;
virtual bool onCommandLoadMachine(std::string path) = 0;
Expand All @@ -63,6 +64,7 @@ class ClemensCommandQueueListener {
virtual void onCommandSendText(std::string text) = 0;
virtual bool onCommandBinaryLoad(std::string pathname, unsigned address) = 0;
virtual bool onCommandBinarySave(std::string pathname, unsigned address, unsigned length) = 0;
virtual void onCommandFastMode(bool enabled) = 0;
};

class ClemensCommandQueue {
Expand Down Expand Up @@ -131,6 +133,8 @@ class ClemensCommandQueue {
void bsave(std::string pathname, unsigned address, unsigned length);
// Load binary from disk
void bload(std::string pathname, unsigned address);
// Toggle fast mode
void fastMode(bool enable);

private:
bool insertDisk(ClemensCommandQueueListener &listener, const std::string_view &inputParam);
Expand Down
Loading

0 comments on commit 502b838

Please sign in to comment.