Skip to content

Commit 1b53560

Browse files
authored
Implement scroll up operation (#46)
* Implement scroll up operation. * Add integration test to make sure scroll up is called.
1 parent cc34898 commit 1b53560

File tree

4 files changed

+103
-1
lines changed

4 files changed

+103
-1
lines changed

chip8/cpu.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ def clear_return(self):
317317
num_lines = self.operand & 0x000F
318318
self.screen.scroll_down(num_lines, self.bitplane)
319319
self.last_op = f"Scroll Down {num_lines:01X}"
320+
elif sub_operation == 0x00D0:
321+
num_lines = self.operand & 0x000F
322+
self.screen.scroll_up(num_lines, self.bitplane)
323+
self.last_op = f"Scroll Up {num_lines:01X}"
320324
else:
321325
try:
322326
self.clear_routines[operation]()

chip8/screen.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def scroll_down(self, num_lines, bitplane):
208208
for y in range(max_y - num_lines, max_y):
209209
self.draw_pixel(x, y, False, bitplane)
210210

211-
# Start copying pixels from the top to the bottom and shift by 4 pixels
211+
# Start copying pixels from the top to the bottom and shift by n pixels
212212
for x in range(max_x):
213213
for y in range(max_y - num_lines - 1, -1, -1):
214214
current_pixel = self.get_pixel(x, y, bitplane)
@@ -220,6 +220,52 @@ def scroll_down(self, num_lines, bitplane):
220220
for y in range(num_lines):
221221
self.draw_pixel(x, y, False, bitplane)
222222

223+
def scroll_up(self, num_lines, bitplane):
224+
"""
225+
Scroll the screen up by num_lines.
226+
227+
:param num_lines: the number of lines to scroll up
228+
:param bitplane: the bitplane to scroll
229+
"""
230+
if bitplane == 0:
231+
return
232+
233+
mode_scale = 1 if self.mode == SCREEN_MODE_EXTENDED else 2
234+
actual_lines = num_lines * mode_scale * self.scale_factor
235+
if bitplane == 3:
236+
self.surface.scroll(0, -actual_lines)
237+
self.surface.fill(
238+
self.pixel_colors[0],
239+
(
240+
0,
241+
self.height * mode_scale * self.scale_factor - actual_lines,
242+
self.width * mode_scale * self.scale_factor,
243+
self.height * mode_scale * self.scale_factor
244+
)
245+
)
246+
self.update()
247+
return
248+
249+
max_x = self.get_width()
250+
max_y = self.get_height()
251+
252+
# Blank out any pixels in the top n lines that we will copy to
253+
for x in range(max_x):
254+
for y in range(num_lines):
255+
self.draw_pixel(x, y, False, bitplane)
256+
257+
# Start copying pixels from the top to the bottom and shift up by n pixels
258+
for x in range(max_x):
259+
for y in range(num_lines, max_y):
260+
current_pixel = self.get_pixel(x, y, bitplane)
261+
self.draw_pixel(x, y, False, bitplane)
262+
self.draw_pixel(x, y - num_lines, current_pixel, bitplane)
263+
264+
# Blank out any pixels in the bottom num_lines horizontal lines
265+
for x in range(max_x):
266+
for y in range(max_y - num_lines, max_y):
267+
self.draw_pixel(x, y, False, bitplane)
268+
223269
def scroll_left(self, bitplane):
224270
"""
225271
Scroll the screen left 4 pixels.

test/test_chip8cpu.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,11 @@ def test_scroll_down_called(self):
852852
self.cpu.clear_return()
853853
self.screen.scroll_down.assert_called_with(4, 1)
854854

855+
def test_scroll_up_called(self):
856+
self.cpu.operand = 0x00D4
857+
self.cpu.clear_return()
858+
self.screen.scroll_up.assert_called_with(4, 1)
859+
855860
def test_scroll_right_called(self):
856861
self.cpu.operand = 0x00FB
857862
self.cpu.clear_return()

test/test_chip8screen.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ def test_scroll_down_bitplane_0_does_nothing(self):
123123
self.assertFalse(self.screen.get_pixel(0, 1, 1))
124124
self.assertFalse(self.screen.get_pixel(0, 1, 2))
125125

126+
def test_scroll_up_bitplane_0_does_nothing(self):
127+
self.screen.init_display()
128+
self.screen.draw_pixel(0, 1, 1, 1)
129+
self.screen.draw_pixel(0, 1, 1, 2)
130+
self.assertTrue(self.screen.get_pixel(0, 1, 1))
131+
self.assertTrue(self.screen.get_pixel(0, 1, 2))
132+
self.screen.scroll_up(1, 0)
133+
self.assertFalse(self.screen.get_pixel(0, 0, 1))
134+
self.assertFalse(self.screen.get_pixel(0, 0, 2))
135+
self.assertTrue(self.screen.get_pixel(0, 1, 1))
136+
self.assertTrue(self.screen.get_pixel(0, 1, 2))
137+
126138
def test_scroll_down_bitplane_1(self):
127139
self.screen.init_display()
128140
self.screen.draw_pixel(0, 0, 1, 1)
@@ -134,6 +146,17 @@ def test_scroll_down_bitplane_1(self):
134146
self.assertTrue(self.screen.get_pixel(0, 1, 1))
135147
self.assertFalse(self.screen.get_pixel(0, 1, 2))
136148

149+
def test_scroll_up_bitplane_1(self):
150+
self.screen.init_display()
151+
self.screen.draw_pixel(0, 1, 1, 1)
152+
self.assertTrue(self.screen.get_pixel(0, 1, 1))
153+
self.assertFalse(self.screen.get_pixel(0, 1, 2))
154+
self.screen.scroll_up(1, 1)
155+
self.assertTrue(self.screen.get_pixel(0, 0, 1))
156+
self.assertFalse(self.screen.get_pixel(0, 0, 2))
157+
self.assertFalse(self.screen.get_pixel(0, 1, 1))
158+
self.assertFalse(self.screen.get_pixel(0, 1, 2))
159+
137160
def test_scroll_down_bitplane_1_both_pixels_active(self):
138161
self.screen.init_display()
139162
self.screen.draw_pixel(0, 0, 1, 1)
@@ -146,6 +169,18 @@ def test_scroll_down_bitplane_1_both_pixels_active(self):
146169
self.assertTrue(self.screen.get_pixel(0, 1, 1))
147170
self.assertFalse(self.screen.get_pixel(0, 1, 2))
148171

172+
def test_scroll_up_bitplane_1_both_pixels_active(self):
173+
self.screen.init_display()
174+
self.screen.draw_pixel(0, 1, 1, 1)
175+
self.screen.draw_pixel(0, 1, 1, 2)
176+
self.assertTrue(self.screen.get_pixel(0, 1, 1))
177+
self.assertTrue(self.screen.get_pixel(0, 1, 2))
178+
self.screen.scroll_up(1, 1)
179+
self.assertTrue(self.screen.get_pixel(0, 0, 1))
180+
self.assertFalse(self.screen.get_pixel(0, 0, 2))
181+
self.assertFalse(self.screen.get_pixel(0, 1, 1))
182+
self.assertTrue(self.screen.get_pixel(0, 1, 2))
183+
149184
def test_scroll_down_bitplane_3_both_pixels_active(self):
150185
self.screen.init_display()
151186
self.screen.draw_pixel(0, 0, 1, 1)
@@ -158,6 +193,18 @@ def test_scroll_down_bitplane_3_both_pixels_active(self):
158193
self.assertTrue(self.screen.get_pixel(0, 1, 1))
159194
self.assertTrue(self.screen.get_pixel(0, 1, 2))
160195

196+
def test_scroll_up_bitplane_3_both_pixels_active(self):
197+
self.screen.init_display()
198+
self.screen.draw_pixel(0, 1, 1, 1)
199+
self.screen.draw_pixel(0, 1, 1, 2)
200+
self.assertTrue(self.screen.get_pixel(0, 1, 1))
201+
self.assertTrue(self.screen.get_pixel(0, 1, 2))
202+
self.screen.scroll_up(1, 3)
203+
self.assertTrue(self.screen.get_pixel(0, 0, 1))
204+
self.assertTrue(self.screen.get_pixel(0, 0, 2))
205+
self.assertFalse(self.screen.get_pixel(0, 1, 1))
206+
self.assertFalse(self.screen.get_pixel(0, 1, 2))
207+
161208
def test_scroll_right_bitplane_0_does_nothing(self):
162209
self.screen.init_display()
163210
self.screen.draw_pixel(0, 0, 1, 1)

0 commit comments

Comments
 (0)