@@ -114,7 +114,7 @@ def __init__(
114
114
0x2 : self .jump_to_subroutine , # 2nnn - CALL nnn
115
115
0x3 : self .skip_if_reg_equal_val , # 3snn - SKE Vs, nn
116
116
0x4 : self .skip_if_reg_not_equal_val , # 4snn - SKNE Vs, nn
117
- 0x5 : self .skip_if_reg_equal_reg , # 5st0 - SKE Vs, Vt
117
+ 0x5 : self .save_skip_routines , # see subfunctions below
118
118
0x6 : self .move_value_to_reg , # 6snn - LOAD Vs, nn
119
119
0x7 : self .add_value_to_reg , # 7snn - ADD Vs, nn
120
120
0x8 : self .execute_logical_instruction , # see subfunctions below
@@ -127,6 +127,12 @@ def __init__(
127
127
0xF : self .misc_routines , # see subfunctions below
128
128
}
129
129
130
+ self .save_skip_lookup = {
131
+ 0x0 : self .skip_if_reg_equal_reg , # 5xy0 - SKE Vx, Vy
132
+ 0x2 : self .store_subset_regs_in_memory , # 5xy2 - STORSUB x, y
133
+ 0x3 : self .read_subset_regs_in_memory , # 5xy3 - LOADSUB x, y
134
+ }
135
+
130
136
self .clear_routines = {
131
137
0xE0 : self .clear_screen , # 00E0 - CLS
132
138
0xEE : self .return_from_subroutine , # 00EE - RTS
@@ -257,21 +263,25 @@ def keyboard_routines(self):
257
263
if self .memory [self .pc - 2 ] == 0xF0 and self .memory [self .pc - 1 ] == 0x00 :
258
264
self .pc += 2
259
265
266
+ def save_skip_routines (self ):
267
+ """
268
+ Will execute either a register save or skip routine.
269
+ """
270
+ operation = self .operand & 0x000F
271
+ try :
272
+ self .save_skip_lookup [operation ]()
273
+ except KeyError :
274
+ raise UnknownOpCodeException (self .operand )
275
+
260
276
def misc_routines (self ):
261
277
"""
262
278
Will execute one of the routines specified in misc_routines.
263
279
"""
264
280
operation = self .operand & 0x00FF
265
- sub_operation = self .operand & 0x000F
266
- if sub_operation == 0x2 :
267
- self .store_subset_regs_in_memory ()
268
- elif sub_operation == 0x3 :
269
- self .read_subset_regs_in_memory ()
270
- else :
271
- try :
272
- self .misc_routine_lookup [operation ]()
273
- except KeyError :
274
- raise UnknownOpCodeException (self .operand )
281
+ try :
282
+ self .misc_routine_lookup [operation ]()
283
+ except KeyError :
284
+ raise UnknownOpCodeException (self .operand )
275
285
276
286
def clear_return (self ):
277
287
"""
@@ -282,7 +292,7 @@ def clear_return(self):
282
292
sub_operation = operation & 0x00F0
283
293
if sub_operation == 0x00C0 :
284
294
num_lines = self .operand & 0x000F
285
- self .screen .scroll_down (num_lines )
295
+ self .screen .scroll_down (num_lines , self . bitplane )
286
296
self .last_op = f"Scroll Down { num_lines :01X} "
287
297
else :
288
298
try :
@@ -296,7 +306,7 @@ def clear_screen(self):
296
306
297
307
Clears the screen
298
308
"""
299
- self .screen .clear_screen ()
309
+ self .screen .clear_screen (self . bitplane )
300
310
self .last_op = "CLS"
301
311
302
312
def return_from_subroutine (self ):
@@ -318,7 +328,7 @@ def scroll_right(self):
318
328
319
329
Scrolls the screen right by 4 pixels.
320
330
"""
321
- self .screen .scroll_right ()
331
+ self .screen .scroll_right (self . bitplane )
322
332
self .last_op = "Scroll Right"
323
333
324
334
def scroll_left (self ):
@@ -327,7 +337,7 @@ def scroll_left(self):
327
337
328
338
Scrolls the screen left by 4 pixels.
329
339
"""
330
- self .screen .scroll_left ()
340
+ self .screen .scroll_left (self . bitplane )
331
341
self .last_op = "Scroll Left"
332
342
333
343
def exit (self ):
@@ -450,6 +460,58 @@ def skip_if_reg_equal_reg(self):
450
460
self .pc += 2
451
461
self .last_op = f"SKE V{ x :01X} , V{ y :01X} "
452
462
463
+ def store_subset_regs_in_memory (self ):
464
+ """
465
+ 5xy2 - STORSUB [I], Vx, Vy
466
+
467
+ Store a subset of registers from x to y in memory starting at index.
468
+ The x and y calculation is as follows:
469
+
470
+ Bits: 15-12 11-8 7-4 3-0
471
+ F x y 2
472
+
473
+ If x is larger than y, then they will be stored in reverse order.
474
+ """
475
+ x = (self .operand & 0x0F00 ) >> 8
476
+ y = (self .operand & 0x00F0 ) >> 4
477
+ pointer = 0
478
+ if y >= x :
479
+ for z in range (x , y + 1 ):
480
+ self .memory [self .index + pointer ] = self .v [z ]
481
+ pointer += 1
482
+ else :
483
+ for z in range (x , y - 1 , - 1 ):
484
+ self .memory [self .index + pointer ] = self .v [z ]
485
+ pointer += 1
486
+
487
+ self .last_op = f"STORSUB [I], { x :01X} , { y :01X} "
488
+
489
+ def read_subset_regs_in_memory (self ):
490
+ """
491
+ 5xy3 - LOADSUB [I], Vx, Vy
492
+
493
+ Load a subset of registers from x to y in memory starting at index.
494
+ The x and y calculation is as follows:
495
+
496
+ Bits: 15-12 11-8 7-4 3-0
497
+ F x y 2
498
+
499
+ If x is larger than y, then they will be loaded in reverse order.
500
+ """
501
+ x = (self .operand & 0x0F00 ) >> 8
502
+ y = (self .operand & 0x00F0 ) >> 4
503
+ pointer = 0
504
+ if y >= x :
505
+ for z in range (x , y + 1 ):
506
+ self .v [z ] = self .memory [self .index + pointer ]
507
+ pointer += 1
508
+ else :
509
+ for z in range (x , y - 1 , - 1 ):
510
+ self .v [z ] = self .memory [self .index + pointer ]
511
+ pointer += 1
512
+
513
+ self .last_op = f"LOADSUB [I], { x :01X} , { y :01X} "
514
+
453
515
def move_value_to_reg (self ):
454
516
"""
455
517
6xnn - LOAD Vx, nn
@@ -781,19 +843,28 @@ def draw_sprite(self):
781
843
self .v [0xF ] = 0
782
844
783
845
if num_bytes == 0 :
784
- self .draw_extended (x_pos , y_pos )
846
+ if self .bitplane == 3 :
847
+ self .draw_extended (x_pos , y_pos , 1 )
848
+ self .draw_extended (x_pos , y_pos , 2 )
849
+ else :
850
+ self .draw_extended (x_pos , y_pos , self .bitplane )
785
851
self .last_op = f"DRAWEX"
786
852
else :
787
- self .draw_normal (x_pos , y_pos , num_bytes )
853
+ if self .bitplane == 3 :
854
+ self .draw_normal (x_pos , y_pos , num_bytes , 1 )
855
+ self .draw_normal (x_pos , y_pos , num_bytes , 2 )
856
+ else :
857
+ self .draw_normal (x_pos , y_pos , num_bytes , self .bitplane )
788
858
self .last_op = f"DRAW V{ x_source :01X} , V{ y_source :01X} "
789
859
790
- def draw_normal (self , x_pos , y_pos , num_bytes ):
860
+ def draw_normal (self , x_pos , y_pos , num_bytes , bitplane ):
791
861
"""
792
862
Draws a sprite on the screen while in NORMAL mode.
793
863
794
864
:param x_pos: the X position of the sprite
795
865
:param y_pos: the Y position of the sprite
796
866
:param num_bytes: the number of bytes to draw
867
+ :param bitplane: the bitplane to draw to
797
868
"""
798
869
for y_index in range (num_bytes ):
799
870
color_byte = self .memory [self .index + y_index ]
@@ -806,13 +877,13 @@ def draw_normal(self, x_pos, y_pos, num_bytes):
806
877
if not self .clip_quirks or (self .clip_quirks and x_coord < self .screen .get_width ()):
807
878
x_coord = x_coord % self .screen .get_width ()
808
879
turned_on = (color_byte & mask ) > 0
809
- current_on = self .screen .get_pixel (x_coord , y_coord )
880
+ current_on = self .screen .get_pixel (x_coord , y_coord , bitplane )
810
881
self .v [0xF ] |= 1 if turned_on and current_on else 0
811
- self .screen .draw_pixel (x_coord , y_coord , turned_on ^ current_on )
882
+ self .screen .draw_pixel (x_coord , y_coord , turned_on ^ current_on , bitplane )
812
883
mask = mask >> 1
813
884
self .screen .update ()
814
885
815
- def draw_extended (self , x_pos , y_pos ):
886
+ def draw_extended (self , x_pos , y_pos , bitplane ):
816
887
"""
817
888
Draws a sprite on the screen while in EXTENDED mode. Sprites in this
818
889
mode are assumed to be 16x16 pixels. This means that two bytes will
@@ -821,6 +892,7 @@ def draw_extended(self, x_pos, y_pos):
821
892
822
893
:param x_pos: the X position of the sprite
823
894
:param y_pos: the Y position of the sprite
895
+ :param bitplane: the bitplane to draw to
824
896
"""
825
897
for y_index in range (16 ):
826
898
for x_byte in range (2 ):
@@ -834,9 +906,9 @@ def draw_extended(self, x_pos, y_pos):
834
906
if not self .clip_quirks or (self .clip_quirks and x_coord < self .screen .get_width ()):
835
907
x_coord = x_coord % self .screen .get_width ()
836
908
turned_on = (color_byte & mask ) > 0
837
- current_on = self .screen .get_pixel (x_coord , y_coord )
909
+ current_on = self .screen .get_pixel (x_coord , y_coord , bitplane )
838
910
self .v [0xF ] += 1 if turned_on and current_on else 0
839
- self .screen .draw_pixel (x_coord , y_coord , turned_on ^ current_on )
911
+ self .screen .draw_pixel (x_coord , y_coord , turned_on ^ current_on , bitplane )
840
912
mask = mask >> 1
841
913
else :
842
914
self .v [0xF ] += 1
@@ -873,58 +945,6 @@ def set_bitplane(self):
873
945
self .bitplane = (self .operand & 0x0F00 ) >> 8
874
946
self .last_op = f"BITPLANE { self .bitplane :01X} "
875
947
876
- def store_subset_regs_in_memory (self ):
877
- """
878
- Fxy2 - STORSUB [I], Vx, Vy
879
-
880
- Store a subset of registers from x to y in memory starting at index.
881
- The x and y calculation is as follows:
882
-
883
- Bits: 15-12 11-8 7-4 3-0
884
- F x y 2
885
-
886
- If x is larger than y, then they will be stored in reverse order.
887
- """
888
- x = (self .operand & 0x0F00 ) >> 8
889
- y = (self .operand & 0x00F0 ) >> 4
890
- pointer = 0
891
- if y >= x :
892
- for z in range (x , y + 1 ):
893
- self .memory [self .index + pointer ] = self .v [z ]
894
- pointer += 1
895
- else :
896
- for z in range (x , y - 1 , - 1 ):
897
- self .memory [self .index + pointer ] = self .v [z ]
898
- pointer += 1
899
-
900
- self .last_op = f"STORSUB [I], { x :01X} , { y :01X} "
901
-
902
- def read_subset_regs_in_memory (self ):
903
- """
904
- Fxy3 - LOADSUB [I], Vx, Vy
905
-
906
- Load a subset of registers from x to y in memory starting at index.
907
- The x and y calculation is as follows:
908
-
909
- Bits: 15-12 11-8 7-4 3-0
910
- F x y 2
911
-
912
- If x is larger than y, then they will be loaded in reverse order.
913
- """
914
- x = (self .operand & 0x0F00 ) >> 8
915
- y = (self .operand & 0x00F0 ) >> 4
916
- pointer = 0
917
- if y >= x :
918
- for z in range (x , y + 1 ):
919
- self .v [z ] = self .memory [self .index + pointer ]
920
- pointer += 1
921
- else :
922
- for z in range (x , y - 1 , - 1 ):
923
- self .v [z ] = self .memory [self .index + pointer ]
924
- pointer += 1
925
-
926
- self .last_op = f"LOADSUB [I], { x :01X} , { y :01X} "
927
-
928
948
def move_delay_timer_into_reg (self ):
929
949
"""
930
950
Fx07 - LOAD Vx, DELAY
0 commit comments