Problem
Chip-8 emulation has inherent flicker problems because the DRW command is dual purpose. Not only is it used to draw pixels but also to un-draw them. So to move a sprite first it is erased, and then drawn in it's new position. If the emulated screen is redrawn during the erase and redraw the sprite will momentarily disappear. More discussion on the topic here Flicker - Chip8 Wiki
Possible solution
One potential solution is to expose an abstraction of the screen, rather than its raw bytes, when vm.screen_rows() is called.
In the vm, at execution of the Draw op, there would be some logic watching for draws that result in only erase of pixels. The pixels that were erased would be tagged with a deadline to be erased later, something like 10 or 20 emulated cycles later. Until the deadline the higher-level vm.screen_rows() would continue to return those pixels as lit. Upon either the deadline being reached, or another Draw command being executed (one which isn't another un-draw), the pixels would finally reflect as un-lit in the higher layer.
This solution shouldn't effect the interpreter accuracy in any way, as all of the memory that could be inspected by the executing Ops would be consistent. It only affects the display layer.
The behavior should be made optional and switchable at runtime.
Problem
Chip-8 emulation has inherent flicker problems because the
DRWcommand is dual purpose. Not only is it used to draw pixels but also to un-draw them. So to move a sprite first it is erased, and then drawn in it's new position. If the emulated screen is redrawn during the erase and redraw the sprite will momentarily disappear. More discussion on the topic here Flicker - Chip8 WikiPossible solution
One potential solution is to expose an abstraction of the screen, rather than its raw bytes, when
vm.screen_rows()is called.In the vm, at execution of the
Drawop, there would be some logic watching for draws that result in only erase of pixels. The pixels that were erased would be tagged with a deadline to be erased later, something like 10 or 20 emulated cycles later. Until the deadline the higher-levelvm.screen_rows()would continue to return those pixels as lit. Upon either the deadline being reached, or anotherDrawcommand being executed (one which isn't another un-draw), the pixels would finally reflect as un-lit in the higher layer.This solution shouldn't effect the interpreter accuracy in any way, as all of the memory that could be inspected by the executing Ops would be consistent. It only affects the display layer.
The behavior should be made optional and switchable at runtime.