Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Index Load Long #39

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions chip8/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def __init__(
# CPU starts with F (e.g. operand Fn07 would call
# self.move_delay_timer_into_reg)
self.misc_routine_lookup = {
0x00: self.index_load_long, # F000 - LOADLONG
0x01: self.set_bitplane, # Fn01 - BITPLANE n
0x07: self.move_delay_timer_into_reg, # Ft07 - LOAD Vt, DELAY
0x0A: self.wait_for_keypress, # Ft0A - KEYD Vt
Expand Down Expand Up @@ -244,11 +245,17 @@ def keyboard_routines(self):

# Skip if the key specified in the source register is pressed
if operation == 0x9E:
self.pc += 2 if keys_pressed[KEY_MAPPINGS[key_to_check]] else 0
if keys_pressed[KEY_MAPPINGS[key_to_check]]:
self.pc += 2
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
self.pc += 2

# Skip if the key specified in the source register is not pressed
if operation == 0xA1:
self.pc += 2 if not keys_pressed[KEY_MAPPINGS[key_to_check]] else 0
if not keys_pressed[KEY_MAPPINGS[key_to_check]]:
self.pc += 2
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
self.pc += 2

def misc_routines(self):
"""
Expand Down Expand Up @@ -396,7 +403,10 @@ def skip_if_reg_equal_val(self):
advancing it by 2 bytes.
"""
x = (self.operand & 0x0F00) >> 8
self.pc += 2 if self.v[x] == (self.operand & 0x00FF) else 0
if self.v[x] == (self.operand & 0x00FF):
self.pc += 2
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
self.pc += 2
self.last_op = f"SKE V{x:01X}, {self.operand & 0x00FF:02X}"

def skip_if_reg_not_equal_val(self):
Expand All @@ -414,7 +424,10 @@ def skip_if_reg_not_equal_val(self):
"""
x = (self.operand & 0x0F00) >> 8
self.last_op = f"SKNE V{x:X}, {self.operand & 0x00FF:02X} (comparing {self.v[x]:02X} to {self.operand & 0xFF:02X})"
self.pc += 2 if self.v[x] != (self.operand & 0x00FF) else 0
if self.v[x] != (self.operand & 0x00FF):
self.pc += 2
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
self.pc += 2

def skip_if_reg_equal_reg(self):
"""
Expand All @@ -431,7 +444,10 @@ def skip_if_reg_equal_reg(self):
"""
x = (self.operand & 0x0F00) >> 8
y = (self.operand & 0x00F0) >> 4
self.pc += 2 if self.v[x] == self.v[y] else 0
if self.v[x] == self.v[y]:
self.pc += 2
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
self.pc += 2
self.last_op = f"SKE V{x:01X}, V{y:01X}"

def move_value_to_reg(self):
Expand Down Expand Up @@ -661,7 +677,10 @@ def skip_if_reg_not_equal_reg(self):
"""
x = (self.operand & 0x0F00) >> 8
y = (self.operand & 0x00F0) >> 4
self.pc += 2 if self.v[x] != self.v[y] else 0
if self.v[x] != self.v[y]:
self.pc += 2
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
self.pc += 2
self.last_op = f"SKNE V{x:01X}, V{y:01X} (comparing {self.v[x]:02X} to {self.v[y]:02X})"

def load_index_reg_with_value(self):
Expand Down Expand Up @@ -823,6 +842,17 @@ def draw_extended(self, x_pos, y_pos):
self.v[0xF] += 1
self.screen.update()

def index_load_long(self):
"""
F000 - LOADLONG

Loads the index register with a 16-bit long value. Consumes the next two
bytes from memory and increments the PC by two bytes.
"""
self.index = (self.memory[self.pc] << 8) + self.memory[self.pc+1]
self.pc += 2
self.last_op = f"LOADLONG {self.index:04X}"

def set_bitplane(self):
"""
Fn01 - BITPLANE n
Expand Down
79 changes: 77 additions & 2 deletions test/test_chip8cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ def test_skip_if_reg_equal_value(self):
else:
self.assertEqual(self.cpu.pc, 0)

def test_skip_if_reg_equal_val_load_long_exception(self):
self.cpu.memory[0x0200] = 0xF0
self.cpu.memory[0x0201] = 0x00
self.cpu.v[1] = 1
self.cpu.operand = 0x3101
self.cpu.skip_if_reg_equal_val()
self.assertEqual(0x0204, self.cpu.pc)

def test_skip_if_reg_not_equal_val(self):
for register in range(0x10):
for value in range(0, 0xFF, 0x10):
Expand All @@ -133,6 +141,14 @@ def test_skip_if_reg_not_equal_val(self):
else:
self.assertEqual(self.cpu.pc, 0)

def test_skip_if_reg_not_equal_val_load_long_exception(self):
self.cpu.memory[0x0200] = 0xF0
self.cpu.memory[0x0201] = 0x00
self.cpu.v[1] = 1
self.cpu.operand = 0x4102
self.cpu.skip_if_reg_not_equal_val()
self.assertEqual(0x0204, self.cpu.pc)

def test_skip_if_reg_equal_reg(self):
for reg_num in range(0x10):
self.cpu.v[reg_num] = reg_num
Expand All @@ -155,6 +171,15 @@ def test_skip_if_reg_equal_reg(self):
else:
self.assertEqual(self.cpu.pc, 0)

def test_skip_if_reg_equal_reg_load_long_exception(self):
self.cpu.memory[0x0200] = 0xF0
self.cpu.memory[0x0201] = 0x00
self.cpu.v[1] = 1
self.cpu.v[2] = 1
self.cpu.operand = 0x5120
self.cpu.skip_if_reg_equal_reg()
self.assertEqual(0x0204, self.cpu.pc)

def test_move_value_to_reg(self):
val = 0x23
for reg_num in range(0x10):
Expand Down Expand Up @@ -410,6 +435,15 @@ def test_skip_if_reg_not_equal_reg(self):
else:
self.assertEqual(self.cpu.pc, 0)

def test_skip_if_reg_not_equal_reg_load_long_exception(self):
self.cpu.memory[0x0200] = 0xF0
self.cpu.memory[0x0201] = 0x00
self.cpu.v[1] = 1
self.cpu.v[2] = 2
self.cpu.operand = 0x9120
self.cpu.skip_if_reg_not_equal_reg()
self.assertEqual(0x0204, self.cpu.pc)

def test_load_index_reg_with_value(self):
for value in range(0x10000):
self.cpu.operand = value
Expand Down Expand Up @@ -679,6 +713,18 @@ def test_operation_9E_pc_skips_if_key_pressed(self):
self.assertTrue(key_mock.asssert_called)
self.assertEqual(2, self.cpu.pc)

def test_operation_9E_pc_skips_if_key_pressed_load_long_exception(self):
self.cpu.operand = 0x09E
self.cpu.v[0] = 1
result_table = [False] * 512
self.cpu.memory[0x0200] = 0xF0
self.cpu.memory[0x0201] = 0x00
result_table[pygame.K_1] = True
with mock.patch("pygame.key.get_pressed", return_value=result_table) as key_mock:
self.cpu.keyboard_routines()
self.assertTrue(key_mock.asssert_called)
self.assertEqual(0x0204, self.cpu.pc)

def test_operation_9E_pc_does_not_skip_if_key_not_pressed(self):
self.cpu.operand = 0x09E
self.cpu.v[0] = 1
Expand All @@ -699,6 +745,17 @@ def test_operation_A1_pc_skips_if_key_not_pressed(self):
self.assertTrue(key_mock.asssert_called)
self.assertEqual(2, self.cpu.pc)

def test_operation_A1_pc_skips_if_key_not_pressed_load_long_exception(self):
self.cpu.operand = 0x0A1
self.cpu.v[0] = 1
result_table = [False] * 512
self.cpu.memory[0x0200] = 0xF0
self.cpu.memory[0x0201] = 0x00
with mock.patch("pygame.key.get_pressed", return_value=result_table) as key_mock:
self.cpu.keyboard_routines()
self.assertTrue(key_mock.asssert_called)
self.assertEqual(0x0204, self.cpu.pc)

def test_operation_A1_pc_does_not_skip_if_key_pressed(self):
self.cpu.operand = 0x0A1
self.cpu.v[0] = 1
Expand Down Expand Up @@ -749,10 +806,10 @@ def test_execute_logical_instruction_raises_exception_on_unknown_op_codes(self):
self.cpu.execute_logical_instruction()

def test_misc_routines_raises_exception_on_unknown_op_codes(self):
self.cpu.operand = 0x0
self.cpu.operand = 0xF0FF
with self.assertRaises(UnknownOpCodeException) as context:
self.cpu.misc_routines()
self.assertEqual("Unknown op-code: 0000", str(context.exception))
self.assertEqual("Unknown op-code: F0FF", str(context.exception))

def test_scroll_down_called(self):
self.cpu.operand = 0x00C4
Expand Down Expand Up @@ -1006,6 +1063,24 @@ def test_read_subset_regs_integration(self):
self.assertEqual(9, self.cpu.v[2])
self.assertEqual(8, self.cpu.v[3])

def test_load_long(self):
self.cpu.index = 0x5000
self.cpu.memory[0x0200] = 0x12
self.cpu.memory[0x0201] = 0x34
self.cpu.index_load_long()
self.assertEqual(0x1234, self.cpu.index)
self.assertEqual(0x0202, self.cpu.pc)

def test_load_long_integration(self):
self.cpu.index = 0x5000
self.cpu.memory[0x0200] = 0xF0
self.cpu.memory[0x0201] = 0x00
self.cpu.memory[0x0202] = 0x12
self.cpu.memory[0x0203] = 0x34
self.cpu.execute_instruction()
self.assertEqual(0x1234, self.cpu.index)
self.assertEqual(0x0204, self.cpu.pc)

# M A I N #####################################################################


Expand Down
Loading