dirkwhoffmann / virtualc64

VirtualC64 is a cycle-accurate C64 emulator for macOS
https://dirkwhoffmann.github.io/virtualc64
Other
342 stars 33 forks source link

Electronic Speech System #785

Closed hipco closed 1 month ago

hipco commented 4 months ago

After V4.5 Ghostbusters and Impossible Mission have a distorted Electronic Speech System output. I've tried many different settings but none of them worked for me. Is there something I'm missing in the machine configuration settings or is it a bug?

mithrendal commented 4 months ago

Did you select the 6581 SID? The newer 8580 does not so well at speach synthesis. Commodore removed a bug in the newer SID which was exploited for speach synthesis.

dirkwhoffmann commented 4 months ago

Confirmed. Something is broken.

hipco commented 4 months ago

Yup, bug. SID 6581 doesn't make any difference.

dirkwhoffmann commented 4 months ago

Seems to work in v4.6. First broken release is v4.7b1

Next step: Determine the faulty commit

hipco commented 4 months ago

Tried V4.6 and the speech synthesis works.

dirkwhoffmann commented 4 months ago

Did a binary search on the repo: Culprit is commit 55aadf4.

dirkwhoffmann commented 4 months ago

Culprit is the CIA sleep logic. Here is the relevant part with an additional if-statement added for debugging:

    // Sleep if threshold is reached
    if (tiredness > 8 && !CIA_ON_STEROIDS) {
        sleep();
        scheduleWakeUp();

        // EXPERIMENTAL TO HUNT DOWN #785
        if (wakeUpCycle <= sleepCycle) {

            printf("Alert: %lld %lld\n", wakeUpCycle, sleepCycle);
            wakeUp();
        }

    } else {
        scheduleNextExecution();
    }

During speech synthesis, the following output is produced:

Alert: 60326377 60326377
Alert: 60331070 60331070
Alert: 60338006 60338006
...

The CIA puts itself to sleep with a wake-up cycle that matches the current clock. In the old code, events were processed after each half-cycle which woke the CIA in the same cycle it fell asleep. In the optimized code (with events only processed once per cycle), the wakeup comes one CPU cycle too late, resulting in a stuttered sound.

Clean fix: Alter the sleep logic such the CIA is only put to rest if it sleeps for at least 'n' cycles (with a suitable 'n').

dirkwhoffmann commented 4 months ago

Here is a small speed-improvement idea. Current code:

void
CIA::serviceEvent(EventID id)
{
    switch(id) {

        case CIA_EXECUTE:

            executeOneCycle();
            break;

        case CIA_WAKEUP:

            wakeUp();
            break;

        default:
            fatalError;
    }
}

Idea: Since CIA_WAKEUP is a rare event, emulation can be sped up by adding a separate CIA_WAKEUP_SLOT in the secondary event table. By doing so, the CIA_EVENT slot would only be responsible for CIA execution. The dispatch function above could be eliminated, and executeOneCycle() could be called directly whenever a CIA event fires.

hipco commented 4 months ago

I'm impressed.

hipco commented 3 months ago

Any news about V4.8?

dirkwhoffmann commented 3 months ago

I'm currently working on v5.0, which will feature run-ahead. It'll still take some time because I've refactored large parts of the code (which broke various stuff), and I am also busy with other projects.

dirkwhoffmann commented 1 month ago

Fixed in v5.0b1