dxxb / sim-arduboy

Arduboy board implementation using simavr
GNU General Public License v3.0
22 stars 8 forks source link

Add support for slowing down emulation #3

Open jessemillar opened 6 years ago

jessemillar commented 6 years ago

Running my .hex file in the sim_arduboy binary results in a play experience roughly 3x faster than it is on the physical Arduboy. Is there a way to limit the draw rate or CPU clock speed in the emulator to more closely match the Arduboy hardware?

dxxb commented 6 years ago

Hi @jessemillar, this function https://github.com/dxxb/sim-arduboy/blob/db7d0ebd8d3f3133f700da18339497a47c969a8c/src/arduboy_avr.c#L83 should already take care of it. It seemed to work pretty well last time I checked but maybe it doesn't in all cases. Do you mind hacking that function to print out deadline_ns and runtime_ns (or a running average of their difference)? I'd like to see what values you are getting on your test machine. Thank you.

jessemillar commented 6 years ago

Sure! I added #include <inttypes.h> to the top of src/arduboy_avr.c and printf("runtime_ns: %" PRIu64 " deadline_ns: %" PRIu64 "\n", runtime_ns, deadline_ns); to avr_callback_sleep_sync(), ran make and then ran sim_arduboy -p 3 ~/Documents/Projects/crates/crates.ino.leonardo.hex like I usually do. The output of starting my game and playing for about a minute is below:

Keymap: 1073741906,1073741905,1073741904,1073741903,122,120
SSD1306: 37uS is 592 cycles for your AVR
SSD1306: 1uS is 16 cycles for your AVR
runtime_ns: 219934594 deadline_ns: 15144062
runtime_ns: 219957972 deadline_ns: 15252562
runtime_ns: 219968177 deadline_ns: 16276562
runtime_ns: 219976056 deadline_ns: 17300562
runtime_ns: 219983666 deadline_ns: 18324562
runtime_ns: 219990446 deadline_ns: 19348562
runtime_ns: 9974704962 deadline_ns: 17505172562
runtime_ns: 17525916577 deadline_ns: 17520532562
runtime_ns: 17525934199 deadline_ns: 17521556562
runtime_ns: 17528812419 deadline_ns: 17537940562
Exiting with error: Invalid argument

This line (runtime_ns: 9974704962 deadline_ns: 17505172562) represents a pause of about two seconds after hitting "play" in my game's menu before it actually starts the game. I'm not sure why that pause happens since it doesn't occur on Arduboy hardware or in ProjectABE (https://felipemanga.github.io/ProjectABE/?skin=Arduboy&url=https://rawgit.com/jessemillar/crates/master/crates.ino.leonardo.hex).

dxxb commented 6 years ago

Some stuttering especially on start maybe inevitable. The issue is that sim-arduboy uses simavr which is more of a simulator than an emulator. It tries to simulate interaction execution timing and pin state changes so they happen with the right timing with respect to the simulated clock but with no regards to wall clock (except for the function I mentioned in my first reply).

What seems very strange is that I expected that function to be called a lot more often. Did you add your print statement above this line? https://github.com/dxxb/sim-arduboy/blob/db7d0ebd8d3f3133f700da18339497a47c969a8c/src/arduboy_avr.c#L93

jessemillar commented 6 years ago

I did add it above that line. I was confused why it wasn't called more frequently too. This is what my copy of avr_callback_sleep_sync() looks like currently:

static void avr_callback_sleep_sync(
                avr_t *avr,
                avr_cycle_count_t how_long)
{
        struct timespec tp;

        /* figure out how long we should wait to match the sleep deadline */
        uint64_t deadline_ns = avr_cycles_to_nsec(avr, avr->cycle + how_long);
        clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
        uint64_t runtime_ns = (tp.tv_sec*1000000000+tp.tv_nsec) - mod_s.start_time_ns;
        printf("runtime_ns: %" PRIu64 " deadline_ns: %" PRIu64 "\n", runtime_ns, deadline_ns);
        if (runtime_ns >= deadline_ns) {
                return;
        }

        uint64_t sleep_us = (deadline_ns - runtime_ns)/1000;
        usleep(sleep_us);
        return;
}
dxxb commented 6 years ago

Need to double check under which conditions avr_callback_sleep_sync() is called currently but I suspect for some reason the game is not letting the CPU idle often so the sleep function does not get called.

jessemillar commented 6 years ago

...a pause of about two seconds after hitting "play" in my game's menu before it actually starts the game. I'm not sure why that pause happens since it doesn't occur on Arduboy hardware or in ProjectABE...

I just realized that I'm calling arduboy.initRandomSeed() when the user presses "PLAY". initRandomSeed() reads from an IO pin which the simulator probably doesn't have access too which would potentially explain the delay.

dlancer commented 6 years ago

@dxxb as I see sim-arduboy do not have any ADC related code. I assume simulation for ADC with floating pin is possible? We can feed ADC port from system random or if this is too slow, just use some pseudo random generator.

dxxb commented 6 years ago

I believe libasimavr supports simulating the ADC. If so, it would be a matter of hooking sim-arduboy into it and feeding the ADC result with some random source.

dlancer commented 6 years ago

I added PR #12 with adc feeding. It pass my tests,but unfortunately delay on start in the Crates game is not related for initRandomSeed()...