Add changeable FPS
This commit is contained in:
parent
3df40f58a5
commit
f8de8aa2cf
|
@ -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`)
|
||||
|
|
58
sipsi-8.py
58
sipsi-8.py
|
@ -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)
|
||||
|
||||
|
|
Loading…
Reference in New Issue