Skip to content

Commit bed04f1

Browse files
authored
Add load long operation. (#39)
1 parent 87c41a7 commit bed04f1

File tree

2 files changed

+113
-8
lines changed

2 files changed

+113
-8
lines changed

chip8/cpu.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ def __init__(
156156
# CPU starts with F (e.g. operand Fn07 would call
157157
# self.move_delay_timer_into_reg)
158158
self.misc_routine_lookup = {
159+
0x00: self.index_load_long, # F000 - LOADLONG
159160
0x01: self.set_bitplane, # Fn01 - BITPLANE n
160161
0x07: self.move_delay_timer_into_reg, # Ft07 - LOAD Vt, DELAY
161162
0x0A: self.wait_for_keypress, # Ft0A - KEYD Vt
@@ -244,11 +245,17 @@ def keyboard_routines(self):
244245

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

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

253260
def misc_routines(self):
254261
"""
@@ -396,7 +403,10 @@ def skip_if_reg_equal_val(self):
396403
advancing it by 2 bytes.
397404
"""
398405
x = (self.operand & 0x0F00) >> 8
399-
self.pc += 2 if self.v[x] == (self.operand & 0x00FF) else 0
406+
if self.v[x] == (self.operand & 0x00FF):
407+
self.pc += 2
408+
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
409+
self.pc += 2
400410
self.last_op = f"SKE V{x:01X}, {self.operand & 0x00FF:02X}"
401411

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

419432
def skip_if_reg_equal_reg(self):
420433
"""
@@ -431,7 +444,10 @@ def skip_if_reg_equal_reg(self):
431444
"""
432445
x = (self.operand & 0x0F00) >> 8
433446
y = (self.operand & 0x00F0) >> 4
434-
self.pc += 2 if self.v[x] == self.v[y] else 0
447+
if self.v[x] == self.v[y]:
448+
self.pc += 2
449+
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
450+
self.pc += 2
435451
self.last_op = f"SKE V{x:01X}, V{y:01X}"
436452

437453
def move_value_to_reg(self):
@@ -661,7 +677,10 @@ def skip_if_reg_not_equal_reg(self):
661677
"""
662678
x = (self.operand & 0x0F00) >> 8
663679
y = (self.operand & 0x00F0) >> 4
664-
self.pc += 2 if self.v[x] != self.v[y] else 0
680+
if self.v[x] != self.v[y]:
681+
self.pc += 2
682+
if self.memory[self.pc - 2] == 0xF0 and self.memory[self.pc - 1] == 0x00:
683+
self.pc += 2
665684
self.last_op = f"SKNE V{x:01X}, V{y:01X} (comparing {self.v[x]:02X} to {self.v[y]:02X})"
666685

667686
def load_index_reg_with_value(self):
@@ -823,6 +842,17 @@ def draw_extended(self, x_pos, y_pos):
823842
self.v[0xF] += 1
824843
self.screen.update()
825844

845+
def index_load_long(self):
846+
"""
847+
F000 - LOADLONG
848+
849+
Loads the index register with a 16-bit long value. Consumes the next two
850+
bytes from memory and increments the PC by two bytes.
851+
"""
852+
self.index = (self.memory[self.pc] << 8) + self.memory[self.pc+1]
853+
self.pc += 2
854+
self.last_op = f"LOADLONG {self.index:04X}"
855+
826856
def set_bitplane(self):
827857
"""
828858
Fn01 - BITPLANE n

test/test_chip8cpu.py

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ def test_skip_if_reg_equal_value(self):
119119
else:
120120
self.assertEqual(self.cpu.pc, 0)
121121

122+
def test_skip_if_reg_equal_val_load_long_exception(self):
123+
self.cpu.memory[0x0200] = 0xF0
124+
self.cpu.memory[0x0201] = 0x00
125+
self.cpu.v[1] = 1
126+
self.cpu.operand = 0x3101
127+
self.cpu.skip_if_reg_equal_val()
128+
self.assertEqual(0x0204, self.cpu.pc)
129+
122130
def test_skip_if_reg_not_equal_val(self):
123131
for register in range(0x10):
124132
for value in range(0, 0xFF, 0x10):
@@ -133,6 +141,14 @@ def test_skip_if_reg_not_equal_val(self):
133141
else:
134142
self.assertEqual(self.cpu.pc, 0)
135143

144+
def test_skip_if_reg_not_equal_val_load_long_exception(self):
145+
self.cpu.memory[0x0200] = 0xF0
146+
self.cpu.memory[0x0201] = 0x00
147+
self.cpu.v[1] = 1
148+
self.cpu.operand = 0x4102
149+
self.cpu.skip_if_reg_not_equal_val()
150+
self.assertEqual(0x0204, self.cpu.pc)
151+
136152
def test_skip_if_reg_equal_reg(self):
137153
for reg_num in range(0x10):
138154
self.cpu.v[reg_num] = reg_num
@@ -155,6 +171,15 @@ def test_skip_if_reg_equal_reg(self):
155171
else:
156172
self.assertEqual(self.cpu.pc, 0)
157173

174+
def test_skip_if_reg_equal_reg_load_long_exception(self):
175+
self.cpu.memory[0x0200] = 0xF0
176+
self.cpu.memory[0x0201] = 0x00
177+
self.cpu.v[1] = 1
178+
self.cpu.v[2] = 1
179+
self.cpu.operand = 0x5120
180+
self.cpu.skip_if_reg_equal_reg()
181+
self.assertEqual(0x0204, self.cpu.pc)
182+
158183
def test_move_value_to_reg(self):
159184
val = 0x23
160185
for reg_num in range(0x10):
@@ -410,6 +435,15 @@ def test_skip_if_reg_not_equal_reg(self):
410435
else:
411436
self.assertEqual(self.cpu.pc, 0)
412437

438+
def test_skip_if_reg_not_equal_reg_load_long_exception(self):
439+
self.cpu.memory[0x0200] = 0xF0
440+
self.cpu.memory[0x0201] = 0x00
441+
self.cpu.v[1] = 1
442+
self.cpu.v[2] = 2
443+
self.cpu.operand = 0x9120
444+
self.cpu.skip_if_reg_not_equal_reg()
445+
self.assertEqual(0x0204, self.cpu.pc)
446+
413447
def test_load_index_reg_with_value(self):
414448
for value in range(0x10000):
415449
self.cpu.operand = value
@@ -679,6 +713,18 @@ def test_operation_9E_pc_skips_if_key_pressed(self):
679713
self.assertTrue(key_mock.asssert_called)
680714
self.assertEqual(2, self.cpu.pc)
681715

716+
def test_operation_9E_pc_skips_if_key_pressed_load_long_exception(self):
717+
self.cpu.operand = 0x09E
718+
self.cpu.v[0] = 1
719+
result_table = [False] * 512
720+
self.cpu.memory[0x0200] = 0xF0
721+
self.cpu.memory[0x0201] = 0x00
722+
result_table[pygame.K_1] = True
723+
with mock.patch("pygame.key.get_pressed", return_value=result_table) as key_mock:
724+
self.cpu.keyboard_routines()
725+
self.assertTrue(key_mock.asssert_called)
726+
self.assertEqual(0x0204, self.cpu.pc)
727+
682728
def test_operation_9E_pc_does_not_skip_if_key_not_pressed(self):
683729
self.cpu.operand = 0x09E
684730
self.cpu.v[0] = 1
@@ -699,6 +745,17 @@ def test_operation_A1_pc_skips_if_key_not_pressed(self):
699745
self.assertTrue(key_mock.asssert_called)
700746
self.assertEqual(2, self.cpu.pc)
701747

748+
def test_operation_A1_pc_skips_if_key_not_pressed_load_long_exception(self):
749+
self.cpu.operand = 0x0A1
750+
self.cpu.v[0] = 1
751+
result_table = [False] * 512
752+
self.cpu.memory[0x0200] = 0xF0
753+
self.cpu.memory[0x0201] = 0x00
754+
with mock.patch("pygame.key.get_pressed", return_value=result_table) as key_mock:
755+
self.cpu.keyboard_routines()
756+
self.assertTrue(key_mock.asssert_called)
757+
self.assertEqual(0x0204, self.cpu.pc)
758+
702759
def test_operation_A1_pc_does_not_skip_if_key_pressed(self):
703760
self.cpu.operand = 0x0A1
704761
self.cpu.v[0] = 1
@@ -749,10 +806,10 @@ def test_execute_logical_instruction_raises_exception_on_unknown_op_codes(self):
749806
self.cpu.execute_logical_instruction()
750807

751808
def test_misc_routines_raises_exception_on_unknown_op_codes(self):
752-
self.cpu.operand = 0x0
809+
self.cpu.operand = 0xF0FF
753810
with self.assertRaises(UnknownOpCodeException) as context:
754811
self.cpu.misc_routines()
755-
self.assertEqual("Unknown op-code: 0000", str(context.exception))
812+
self.assertEqual("Unknown op-code: F0FF", str(context.exception))
756813

757814
def test_scroll_down_called(self):
758815
self.cpu.operand = 0x00C4
@@ -1006,6 +1063,24 @@ def test_read_subset_regs_integration(self):
10061063
self.assertEqual(9, self.cpu.v[2])
10071064
self.assertEqual(8, self.cpu.v[3])
10081065

1066+
def test_load_long(self):
1067+
self.cpu.index = 0x5000
1068+
self.cpu.memory[0x0200] = 0x12
1069+
self.cpu.memory[0x0201] = 0x34
1070+
self.cpu.index_load_long()
1071+
self.assertEqual(0x1234, self.cpu.index)
1072+
self.assertEqual(0x0202, self.cpu.pc)
1073+
1074+
def test_load_long_integration(self):
1075+
self.cpu.index = 0x5000
1076+
self.cpu.memory[0x0200] = 0xF0
1077+
self.cpu.memory[0x0201] = 0x00
1078+
self.cpu.memory[0x0202] = 0x12
1079+
self.cpu.memory[0x0203] = 0x34
1080+
self.cpu.execute_instruction()
1081+
self.assertEqual(0x1234, self.cpu.index)
1082+
self.assertEqual(0x0204, self.cpu.pc)
1083+
10091084
# M A I N #####################################################################
10101085

10111086

0 commit comments

Comments
 (0)