Closed colin-broderick closed 3 years ago
I think I understand and yeah it's probably something we should discuss over skype.
The model I've had in my head so far, syncs components up by making them wait for each other if necessary. For example, each component could have a 'ready to move on' variable that the other components check on when they need to. Or something along those lines.
Another idea: Each component has an internal variable keeping track of what cycle it thinks it's on. Then when necessary, we force all components to add false cycles until they all equal the highest one.
Ticking the cycles forward would then just be a case of replacing every sem.wait() with a tick advancing function.
Timing rewrite tasks
CPU
class which keeps track of available clock cycles. The initial value should be set to zero.CPU::run()
method to take a number of cycles as an argument. This number is added to the total available cycles count in the class instance.CPU::run()
executes, for each instruction it deducts the appropriate amount of cycles from the internal count, i.e. this->cycles--;
while (true)
to while (this->cycles > 0)
. Note that the cycle count may become slightly negative since different instructions take different amounts of cycles to execute, so we can't guarantee we'll land on zero.CPU::run()
returns either the number of cycles consumed or the number of cycles remaining. Haven't decided yet. We'll see what falls out as most useful when we start writing.Once these are implemented the CPU can be told to run for a specific number of cycles. We can them run the CPU for (e.g.) the number of cycles in a single video frame, then wait until the next frame to run the same number again.
This was implemented except that I had CPU::run return some status code. The system will run until the CPU returns a BREAK error code.
@Mark-Platts
After reading around a bit I've decided I definitely want to change the way timing is done. It's not scalable. Trying to tie it to real time was a mistake from the start.
The way most people seem to do it is just work out how many cycles are in a single frame (assuming 60 Hz or whatever) and just simulate that many cycles at full speed, then sleep for the remainder of the time, and do it again after the PPU has drawn a frame.
My only concern there is syncing time with other components. But maybe it's not as critical as I think, because nobody seems concerned. The issue is that cycle count obviously doesn't correspond to instruction count directly, so the PPU might start drawing when the CPU is at the start of an instruction, or in the middle, or at the end, and potentially get different results. It's hard to explain in text but we can discuss it next call and see what you think.