Add changeable FPS

This commit is contained in:
Juhani Krekelä 2018-09-22 18:28:01 +03:00
parent 3df40f58a5
commit f8de8aa2cf
2 changed files with 51 additions and 13 deletions

View File

@ -34,6 +34,12 @@ Emulation speed
---------------
Instructions are run 500 times a second
Issues
------
* Player sprites tend to flicker. (See e.g. BRIX) Why? Also, this seems to
happen in the haxe-chip-8-emulator too, and lowering the FPS doesn't seem
to help, which suggests something fishy with the programs
Requirements
------------
* pyglet (`pip3 install pyglet`)

View File

@ -40,10 +40,11 @@ def key_released(symbol):
break
def draw_screen():
global display_screen
to_draw = []
for y in range(32):
for x in range(64):
if screen[y * 64 + x]:
if display_screen[y * 64 + x]:
to_draw.append((x, y))
screen_points = []
@ -223,10 +224,24 @@ def step():
# Dxyn draw vx, vy, n
elif high_byte >> 4 == 0xD:
# TODO: OSCOM Nano manual (page 38) says "<The screen
# behaves as if the top was connected to the bottom and
# the sides to each other.>" Investigate how this wrapping
# should be implemented
# OSCOM Nano manual (page 38) says "<The screen behaves as
# if the top was connected to the bottom and the sides to
# each other>", but I can't find any info on how to do this
# wrapping on the generally used sources.
#
# https://github.com/AfBu/haxe-chip-8-emulator looks like
# it wraps the pixels to the next row down, but as it
# doesn't seem to handle drawing out the bottom of the
# screen at all, unsure how intentional this is.
#
# https://github.com/dmatlack/chip8 wraps the pixels on the
# other side of the same line.
#
# The game "Blitz" seems to require draws off the bottom of
# the screen to not result in anything. Therefore, as I
# have yet to find any games that break with it, I'm just
# skipping pixels that fall outside the screen.
x_start = data_registers[high_byte & 0xf]
y_start = data_registers[low_byte >> 4]
@ -239,14 +254,12 @@ def step():
y = y_start + dy
# Screen is 32 lines tall
if y >= 32:
# TODO: Figure how y >= 32 works
continue
for dx in range(8):
x = x_start + dx
# Screen is 64 columns wide
if x >= 64:
# TODO: Figure how x >= 64 works
continue
# Pixels are stored MSB-left
@ -368,16 +381,26 @@ def tick_timers():
sound_timer = 0
def advance_interpreter(dt):
global cpu_speed
global cpu_cycles_to_go
# Each tic (60Hz) we need to run cpu_clock / 60Hz cycles
global cpu_clock
global screen, display_screen, screen_fps
global cpu_cycles_to_go, frames_to_go
# Each tic (60Hz) we need to run cpu_clock / 60Hz cycles and
# draw screen_fps / 60 frames
cpu_cycles_to_go += cpu_clock / 60
frames_to_go += screen_fps / 60
tick_timers()
while cpu_cycles_to_go >= 1:
step()
cpu_cycles_to_go -= 1
if frames_to_go >= 1:
# Only draw the latest frame. This means FPS >60 won't work
# but why would you ever want to run chip-8 faster than
# that
display_screen = screen[:]
frames_to_go -= int(frames_to_go)
def initialize_ram():
global ram, font_start
ram = [0]*(1<<12)
@ -613,8 +636,11 @@ def initialize_ram():
#ram[0x200:len(test_program) + 0x200] = test_program
def initialize_screen():
global screen
global screen, display_screen, screen_fps
screen = [False] * 64 * 32
display_screen = screen[:]
# TODO: Support changing FPS
screen_fps = 60
def initialize_timers():
global delay_timer, sound_timer
@ -654,10 +680,14 @@ def load_program(f):
def main():
global window
global cpu_cycles_to_go
# Don't hardcode the size
global cpu_cycles_to_go, frames_to_go
# TODO: Don't hardcode the size
window = pyglet.window.Window(640, 320, resizable = True)
# Don't use pulse driver, as it is really buggy and can crash the
# python process
pyglet.options['audio'] = ('openal', 'directsound', 'silent')
# Hook up our screen drawing routine
@window.event
def on_draw():
@ -680,10 +710,12 @@ def main():
initialize_keyboard()
initialize_cpu()
# TODO: Deal with missing file gracefully
with open(sys.argv[1], 'rb') as f:
load_program(f)
cpu_cycles_to_go = 0
frames_to_go = 0
# Start the emulation
pyglet.clock.schedule_interval(advance_interpreter, 1/60)