diff --git a/README.md b/README.md index e267de8..3853d25 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ An Octo compatible XO Chip, Super Chip, and Chip 8 emulator. 4. [Running](#running) 1. [Running a ROM](#running-a-rom) 2. [Screen Scale](#screen-scale) - 3. [Execution Delay](#execution-delay) + 3. [Instructions Per Second](#instructions-per-second) 4. [Quirks Modes](#quirks-modes) 1. [Shift Quirks](#shift-quirks) 2. [Index Quirks](#index-quirks) @@ -207,18 +207,14 @@ scale is 64 x 32): The command above will scale the window so that it is 10 times the normal size. -### Execution Delay +### Instructions Per Second -You may also wish to experiment with the `--delay` switch, which instructs -the emulator to add a delay to every operation that is executed. For example, +The `--ticks` switch will limit the number of instructions per second that the +emulator is allowed to run. By default, the value is set to 1,000. Minimum values +are 200. Use this switch to adjust the running time of ROMs that execute too quickly. +For simplicity, each instruction is assumed to take the same amount of time. - python yac8e.py /path/to/rom/filename --delay 10 - -The command above will add a 10 ms delay to every opcode that is executed. -This is useful for very fast computers (note that it is difficult to find -information regarding opcode execution times, as such, I have not attempted -any fancy timing mechanisms to ensure that instructions are executed in a -set amount of time). + python yac8e.py /path/to/rom/filename --ticks 2000 ### Quirks Modes diff --git a/chip8/cpu.py b/chip8/cpu.py index 8de9477..e3f813c 100644 --- a/chip8/cpu.py +++ b/chip8/cpu.py @@ -84,7 +84,8 @@ def __init__( jump_quirks=False, clip_quirks=False, logic_quirks=False, - mem_size="64K" + mem_size="64K", + max_ticks=1000, ): """ Initialize the Chip8 CPU. The only required parameter is a screen @@ -98,6 +99,7 @@ def __init__( :param clip_quirks: enables screen clipping quirks :param logic_quirks: enables logic quirks :param mem_size: sets the maximum memory available "4K" or "64K" + :param max_ticks: sets the maximum allowable operations per second """ self.last_pc = 0x0000 self.last_op = "None" @@ -109,6 +111,11 @@ def __init__( self.index = 0 self.rpl = [0] * NUM_REGISTERS + self.tick_counter = 0 + self.max_ticks = max_ticks + if self.max_ticks < 200: + self.max_ticks = 200 + self.pitch = 64 self.playback_rate = 4000 self.audio_pattern_buffer = [0] * 16 @@ -226,6 +233,9 @@ def execute_instruction(self, operand=None): :param operand: the operand to execute :return: returns the operand executed """ + if self.tick_counter > self.max_ticks: + return None + self.last_pc = self.pc if operand: self.operand = operand @@ -236,6 +246,7 @@ def execute_instruction(self, operand=None): self.pc += 2 operation = (self.operand & 0xF000) >> 12 self.operation_lookup[operation]() + self.tick_counter += 1 return self.operand def execute_logical_instruction(self): @@ -1249,6 +1260,7 @@ def reset(self): self.sound_playing = False self.sound_waveform = None self.bitplane = 1 + self.tick_counter = 0 def load_rom(self, filename, offset=PROGRAM_COUNTER_START): """ @@ -1269,6 +1281,8 @@ def decrement_timers(self): """ Decrement both the sound and delay timer. """ + self.tick_counter = 0 + self.delay -= 1 if self.delay > 0 else 0 self.sound -= 1 if self.delay > 0 else 0 if self.sound > 0 and not self.sound_playing: diff --git a/chip8/emulator.py b/chip8/emulator.py index f751749..8338dc8 100644 --- a/chip8/emulator.py +++ b/chip8/emulator.py @@ -22,6 +22,7 @@ def main_loop(args): :param args: the parsed command-line arguments """ delay_timer_event = 24 + max_ticks = int(args.ticks / 60) screen = Chip8Screen( scale_factor=args.scale, @@ -39,6 +40,7 @@ def main_loop(args): clip_quirks=args.clip_quirks, logic_quirks=args.logic_quirks, mem_size=args.mem_size, + max_ticks=max_ticks ) cpu.load_rom(FONT_FILE, 0) cpu.load_rom(args.rom) @@ -47,8 +49,6 @@ def main_loop(args): pygame.time.set_timer(delay_timer_event, 17) while cpu.running: - pygame.time.wait(args.op_delay) - if not cpu.awaiting_keypress: cpu.execute_instruction() diff --git a/yac8e.py b/yac8e.py index 51d0424..c8f5432 100755 --- a/yac8e.py +++ b/yac8e.py @@ -33,9 +33,8 @@ def parse_arguments(): "--scale", help="the scale factor to apply to the display " "(default is 5)", type=int, default=5, dest="scale") parser.add_argument( - "--delay", help="sets the CPU operation to take at least " - "the specified number of milliseconds to execute (default is 1)", - type=int, default=1, dest="op_delay") + "--ticks", help="how many instructions per second are allowed", + type=int, default=1000, dest="ticks") parser.add_argument( "--shift_quirks", help="Enable shift quirks", action="store_true", dest="shift_quirks"