@@ -36,7 +36,7 @@ class UnknownOpCodeException(Exception):
36
36
A class to raise unknown op code exceptions.
37
37
"""
38
38
def __init__ (self , op_code ):
39
- Exception .__init__ (self , f"Unknown op-code: { op_code :X } " )
39
+ Exception .__init__ (self , f"Unknown op-code: { op_code :04X } " )
40
40
41
41
42
42
class Chip8CPU :
@@ -94,6 +94,8 @@ def __init__(
94
94
self .pitch = 64
95
95
self .playback_rate = 4000
96
96
97
+ self .bitplane = 1
98
+
97
99
self .shift_quirks = shift_quirks
98
100
self .index_quirks = index_quirks
99
101
self .jump_quirks = jump_quirks
@@ -125,6 +127,16 @@ def __init__(
125
127
0xF : self .misc_routines , # see subfunctions below
126
128
}
127
129
130
+ self .clear_routines = {
131
+ 0xE0 : self .clear_screen , # 00E0 - CLS
132
+ 0xEE : self .return_from_subroutine , # 00EE - RTS
133
+ 0xFB : self .scroll_right , # 00FB - SCRR
134
+ 0xFC : self .scroll_left , # 00FC - SCRL
135
+ 0xFD : self .exit , # 00FD - EXIT
136
+ 0xFE : self .disable_extended_mode , # 00FE - SET NORMAL
137
+ 0xFF : self .enable_extended_mode , # 00FF - SET EXTENDED
138
+ }
139
+
128
140
# This set of operations is invoked when the operand loaded into the
129
141
# CPU starts with 8 (e.g. operand 8nn0 would call
130
142
# self.move_reg_into_reg)
@@ -144,6 +156,7 @@ def __init__(
144
156
# CPU starts with F (e.g. operand Fn07 would call
145
157
# self.move_delay_timer_into_reg)
146
158
self .misc_routine_lookup = {
159
+ 0x01 : self .set_bitplane , # Fn01 - BITPLANE n
147
160
0x07 : self .move_delay_timer_into_reg , # Ft07 - LOAD Vt, DELAY
148
161
0x0A : self .wait_for_keypress , # Ft0A - KEYD Vt
149
162
0x15 : self .move_reg_into_delay_timer , # Fs15 - LOAD DELAY, Vs
@@ -249,50 +262,29 @@ def misc_routines(self):
249
262
250
263
def clear_return (self ):
251
264
"""
252
- Opcodes starting with a 0 are one of the following instructions:
253
-
254
- 0nnn - Jump to machine code function (ignored)
255
- 00Cn - Scroll n pixels down
256
- 00E0 - Clear the display
257
- 00EE - Return from subroutine
258
- 00FB - Scroll 4 pixels right
259
- 00FC - Scroll 4 pixels left
260
- 00FD - Exit
261
- 00FE - Disable extended mode
262
- 00FF - Enable extended mode
265
+ Opcodes starting with a 0 usually correspond to screen clearing or scrolling
266
+ routines, or emulator exit routines.
263
267
"""
264
268
operation = self .operand & 0x00FF
265
269
sub_operation = operation & 0x00F0
266
270
if sub_operation == 0x00C0 :
267
271
num_lines = self .operand & 0x000F
268
272
self .screen .scroll_down (num_lines )
269
273
self .last_op = f"Scroll Down { num_lines :01X} "
274
+ else :
275
+ try :
276
+ self .clear_routines [operation ]()
277
+ except KeyError :
278
+ raise UnknownOpCodeException (self .operand )
270
279
271
- if operation == 0x00E0 :
272
- self .screen .clear_screen ()
273
- self .last_op = "CLS"
274
-
275
- if operation == 0x00EE :
276
- self .return_from_subroutine ()
277
-
278
- if operation == 0x00FB :
279
- self .screen .scroll_right ()
280
- self .last_op = "Scroll Right"
281
-
282
- if operation == 0x00FC :
283
- self .screen .scroll_left ()
284
- self .last_op = "Scroll Left"
285
-
286
- if operation == 0x00FD :
287
- self .running = False
288
-
289
- if operation == 0x00FE :
290
- self .disable_extended_mode ()
291
- self .last_op = "Set Normal Mode"
280
+ def clear_screen (self ):
281
+ """
282
+ 00E0 - CLS
292
283
293
- if operation == 0x00FF :
294
- self .enable_extended_mode ()
295
- self .last_op = "Set Extended Mode"
284
+ Clears the screen
285
+ """
286
+ self .screen .clear_screen ()
287
+ self .last_op = "CLS"
296
288
297
289
def return_from_subroutine (self ):
298
290
"""
@@ -307,6 +299,53 @@ def return_from_subroutine(self):
307
299
self .pc += self .memory [self .sp ]
308
300
self .last_op = "RTS"
309
301
302
+ def scroll_right (self ):
303
+ """
304
+ 00FB - SCRR
305
+
306
+ Scrolls the screen right by 4 pixels.
307
+ """
308
+ self .screen .scroll_right ()
309
+ self .last_op = "Scroll Right"
310
+
311
+ def scroll_left (self ):
312
+ """
313
+ 00FC - SCRL
314
+
315
+ Scrolls the screen left by 4 pixels.
316
+ """
317
+ self .screen .scroll_left ()
318
+ self .last_op = "Scroll Left"
319
+
320
+ def exit (self ):
321
+ """
322
+ 00FD - EXIT
323
+
324
+ Exits the emulator.
325
+ """
326
+ self .running = False
327
+ self .last_op = "EXIT"
328
+
329
+ def disable_extended_mode (self ):
330
+ """
331
+ 00FE - SET NORMAL
332
+
333
+ Disables extended mode.
334
+ """
335
+ self .screen .set_normal ()
336
+ self .mode = MODE_NORMAL
337
+ self .last_op = "Set Normal Mode"
338
+
339
+ def enable_extended_mode (self ):
340
+ """
341
+ 00FF - SET EXTENDED
342
+
343
+ Set extended mode.
344
+ """
345
+ self .screen .set_extended ()
346
+ self .mode = MODE_EXTENDED
347
+ self .last_op = "Set Extended Mode"
348
+
310
349
def jump_to_address (self ):
311
350
"""
312
351
1nnn - JUMP nnn
@@ -778,6 +817,26 @@ def draw_extended(self, x_pos, y_pos):
778
817
self .v [0xF ] += 1
779
818
self .screen .update ()
780
819
820
+ def set_bitplane (self ):
821
+ """
822
+ Fn01 - BITPLANE n
823
+
824
+ Selects the active bitplane for screen drawing operations. Bitplane
825
+ selection is as follows:
826
+
827
+ 0 - no bitplane selected
828
+ 1 - first bitplane selected
829
+ 2 - second bitplane selected
830
+ 3 - first and second bitplane selected
831
+
832
+ The bitplane selection values is as follows:
833
+
834
+ Bits: 15-12 11-8 7-4 3-0
835
+ F n 0 1
836
+ """
837
+ self .bitplane = (self .operand & 0x0F00 ) >> 8
838
+ self .last_op = f"BITPLANE { self .bitplane :01X} "
839
+
781
840
def move_delay_timer_into_reg (self ):
782
841
"""
783
842
Fx07 - LOAD Vx, DELAY
@@ -1031,6 +1090,7 @@ def reset(self):
1031
1090
self .rpl = [0 ] * NUM_REGISTERS
1032
1091
self .pitch = 64
1033
1092
self .playback_rate = 4000
1093
+ self .bitplane = 1
1034
1094
1035
1095
def load_rom (self , filename , offset = PROGRAM_COUNTER_START ):
1036
1096
"""
@@ -1054,18 +1114,5 @@ def decrement_timers(self):
1054
1114
self .delay -= 1 if self .delay > 0 else 0
1055
1115
self .sound -= 1 if self .delay > 0 else 0
1056
1116
1057
- def enable_extended_mode (self ):
1058
- """
1059
- Set extended mode.
1060
- """
1061
- self .screen .set_extended ()
1062
- self .mode = MODE_EXTENDED
1063
-
1064
- def disable_extended_mode (self ):
1065
- """
1066
- Disables extended mode.
1067
- """
1068
- self .screen .set_normal ()
1069
- self .mode = MODE_NORMAL
1070
1117
1071
1118
# E N D O F F I L E ########################################################
0 commit comments