Need help designing an emulator

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
JustClaire
Posts: 18
Joined: 27 Feb 2020

Need help designing an emulator

Post by JustClaire »

Hello

I have been making an emulator for 6502 for the past week but i am stuck at an issue.
WARNING: this question is not entirely about 6502, but more about emulator design in general.

The CPU emulation code can currently run at ~70-80MHz on average, but i am having trouble controlling the frequency precisely. I want my code to work multiplatform but Afaik windows api does not allow for nanosecond precision timers unlike unix so i cannot set the emulator to run precisely at a few MHz.

It is kind of ironic that the issue is running code slower than its max speed.

What would be the preferred approach to control emulator frequency? I want to be able to at least run it at the max datasheet frequency of 14MHz if its possible
White Flame
Posts: 704
Joined: 24 Jul 2012

Re: Need help designing an emulator

Post by White Flame »

Consider your "speed" as the number of cycles you take in some larger sensible time period. For many video-oriented machines, you'd run a frame at a time, then sync to the wall clock to a 1/50th or 1/60th second delta from the last time, outputting the single generated frame & any audio buffers.

Say you're going to run at 1MHz, and you wanted to sync time every 10ms; so you'd check the current time, run 10,000 clock cycles flat-out, then wait for 10ms to have elapsed, and loop. For 2MHz, run 20,000 cycles and sync on 10ms. If your target time has already elapsed, that means your emulation isn't keeping up in real-time. You don't need high-resolution timers in this approach.

You don't need every cycle to line up with the wall clock, unless your code is interfacing with actual hardware peripherals (say, emulating a serial port connected to real pins).
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Re: Need help designing an emulator

Post by BitWise »

JustClaire wrote:
Hello
The CPU emulation code can currently run at ~70-80MHz on average, but i am having trouble controlling the frequency precisely. I want my code to work multiplatform but Afaik windows api does not allow for nanosecond precision timers unlike unix so i cannot set the emulator to run precisely at a few MHz.
You could write a Windows implementation of 'usleep' using the Windows function 'QueryPerformanceCounter' to delay your code based on the cycle length of the emulated instruction. Sadly its a busy wait.
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: Need help designing an emulator

Post by BigEd »

If you have any kind of user interface, you might be using (or consider using) the SDL cross-platform library, which offers timers.

If White Flame's idea of syncing at approx a video frame rate is too coarse, consider syncing at approx a video horizontal line rate.
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: Need help designing an emulator

Post by drogon »

JustClaire wrote:
Hello

I have been making an emulator for 6502 for the past week but i am stuck at an issue.
WARNING: this question is not entirely about 6502, but more about emulator design in general.

The CPU emulation code can currently run at ~70-80MHz on average, but i am having trouble controlling the frequency precisely. I want my code to work multiplatform but Afaik windows api does not allow for nanosecond precision timers unlike unix so i cannot set the emulator to run precisely at a few MHz.

It is kind of ironic that the issue is running code slower than its max speed.

What would be the preferred approach to control emulator frequency? I want to be able to at least run it at the max datasheet frequency of 14MHz if its possible
One thing to note is that not all Unixes/Linuxes/BSDs/etc. have nanosecond resolution and sometimes other means have to be employed. And even if you do have seemingly ns timing, you should always check the minimum interval possible - use the clock_getres(2) system call to see what's possible. also check the minimum duration of a system call - especially things like sleep(), nanosleep(), etc. you may well find that they are much longer than you're expecting.

One thing I did for my cycle-accurate PDP-8 emulator a while back was to bypass the kernel and use a hardware timer because the system I was running it on only had a resolution of 1µS and I needed something quicker - that was on a Raspberry Pi Zero and obviously isn't possibly on all platforms. So my strategy was:
  • Read the hardware timer (A)
  • execute my C code to Interpret the instruction
  • Read the hardware timer again and use it to calculate the time left to the next clock tick (cycleTime - (current - A))
  • Busy loop for this time, reading/comparing the hardware timer
That works remarkably well and I was able to check my cycle timing against a real PDP-8 and they matched.

Personally, cycle accurate is the way to go because (other than the fun with a PiTubeDirect - 65C02 @ 300Mhz) then if you want faster you might as well use a different CPU IMO ... (although there are scenarios like ... that obscure bug that only happens once a day where speeding up the emulating might help debug it, etc. but then how did they do it on the old days...)

Cheers,

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
jmthompson
Posts: 127
Joined: 30 Dec 2017
Location: Detroit, Michigan, USA
Contact:

Re: Need help designing an emulator

Post by jmthompson »

In pretty much any full system emulation there will be a need to match the emulated CPU speed with the emulated hardware, and so the CPU speed needs to be controlled at that level, not inside the CPU emulation. All you really need is to provide a single method that takes as input the maximum number of CPU cycles to execute, and that then returns the number of actual cycles that were executed. This is what I did with M65816, the CPU emulator inside XGS.

With this setup, you can set your timer to a more reasonable period, and just keep the CPU speed constant by making sure you run about the same number of cycles for each timer period. XGS for example runs its timer at the video frame rate, and then runs the CPU emulation in between generating the scan lines of the current frame. The frame rate is fixed to real time (50 or 60 fps), and so as long as it's running about the right number of CPU cycles per timer period the CPU emulation will stay at the selected speed.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: Need help designing an emulator

Post by Chromatix »

You can still use relatively coarse wall-clock timing while accurately simulating a full system. You advance all the hardware at the same time, not just the CPU, until your designated cycle count has elapsed. That is then the moment to synchronise the internal machine state with the external view of it, including real time.
Post Reply